home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / Mac OS USB DDK / Examples / PrinterClassDriver / PrinterClassDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-10  |  105.1 KB  |  3,126 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PrinterClassDriver.c
  3.  
  4.     Contains:    MacOS USB printer class driver
  5.                 [ref. IEEE Std 1284-1994]
  6.  
  7.     Version:    xxx put version here xxx
  8.  
  9.  
  10.  
  11.     Copyright:    1998 by Apple Computer, Inc., all rights reserved.
  12.  
  13. */
  14.  
  15.  
  16. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  17.     includes
  18.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  19. #include <Devices.h>
  20. #include <DriverServices.h>
  21. #include <Interrupts.h>
  22. #include <LowMem.h>
  23. #include <Folders.h>
  24. #include <String.h>
  25. #include <stdio.h>
  26. #include <USB.h>
  27.  
  28. #ifndef __CODEFRAGMENTS__
  29. #include <codefragments.h>
  30. #endif
  31.  
  32. #include "PrinterClassDriver.h"
  33. #include "TradDriverLoaderLib.h"
  34.  
  35. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  36.     constants
  37.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  38. #define MAX_SUFFIX                    127        // maximum copies we'll enter in unit table
  39. #define kUSBParallelDrvrRsrcID    12
  40. #define kMinDrvrUnitNumber            48            // minimum unit table entry which we'll install
  41. #define kUSS720MillisecondDelay    3*1000    // poll every three seconds
  42. #define kUSS720StatusMSDelay        10            // poll one hundred times per second
  43. #define MAX_USB_TRANSFER_SIZE        TRANSFER_SIZE            // zero acts as manifest for conditional compilation
  44.  
  45. #define kUSBAttributeBulk            0x02
  46. #define kUSBInputEndpointMask        0x80
  47.  
  48. enum
  49. {
  50.     kCString = 0,                // StateStr, USBStatusStr selector
  51.     kPString,                    // StateStr, USBStatusStr selector
  52.     kDrvrFirstDigit = 5        // length_byte + ".USB" = 5
  53. };
  54. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  55.     manifest constants
  56. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  57. //
  58. //    DEBUGGING                        extra debugging information to USB Expert Log
  59. //    DOUBLE_BUFFER                    use a page aligned buffer in system heap to double buffer app i/o
  60. //    LOG                                echo all the write data to a log file in the system folder
  61. // LOCK_MEMORY                        LockMemory on the i/o buffer before write and unlock on write completion
  62. // VIRTUAL_MEMORY_CHECK            check the physical addresses of the buffer we pass for write requests
  63. // MACSBUG_ON_READ                break into MacsBug before each read request
  64. //    MACSBUG_ON_READ_COMPLETE    break into MacsBug at each read completion routine
  65. //    MACSBUG_ON_WRITE                break into MacsBug on each write request
  66. // MACSBUG_ON_WRITE_COMPLETE    break into MacsBug at each write completion routine
  67. //
  68. #define DEBUGGING                        0    /* DEBUGGING */
  69. #define DOUBLE_BUFFER                    1    /* DOUBLE_BUFFER */
  70. #define LOG                                0    /* LOG */
  71. #define LOCK_MEMORY                        1    /* LOCK_MEMORY */
  72. #define MACSBUG_ON_READ                    1    /* MACSBUG_ON_READ */
  73. #define MACSBUG_ON_READ_COMPLETE        0    /* MACSBUG_ON_READ_COMPLETE */ 
  74. #define MACSBUG_ON_WRITE                1    /* MACSBUG_ON_WRITE */
  75. #define MACSBUG_ON_WRITE_COMPLETE        0    /* MACSBUG_ON_WRITE_COMPLETE */ 
  76. #define VIRTUAL_MEMORY_CHECK            0    /* VIRTUAL_MEMORY_CHECK require LOCK_MEMORY, currently broken */
  77.  
  78. #if LOG
  79. #define LOGGING(x)    x
  80. #include <stdio.h>
  81. #else
  82. #define LOGGING(x)
  83. #endif
  84.  
  85. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  86.     globals
  87.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  88. static struct usbPrinterPBStruct    printerClassRecord;
  89. static FSSpec                            printerClassDriverFileSpec;
  90. LOGGING( static FILE                    *logfile );
  91. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  92.     prototypes
  93.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  94.  
  95. static void    PrinterDeviceCompletionProc(USBPB *pb);
  96. static void SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb );
  97. static void    SoftReset( USBPB *usbprint, short interfaceNum );
  98. static void    CapabilityRequest( USBPB *pb, Ptr p, long length, short config, short interfaceNum, short alternateSetting );
  99. static void    CentronicsStatus( USBPB *usbprint, Ptr p, short interfaceNum );
  100. static void CompletionProc(USBPB *pb);
  101. static int    cstrlen( char *p );
  102. static void    cstrcpy( char *dst, char *src );
  103. static void    cstrcat( char *dst, char *src );
  104.  
  105. void            PrinterDeviceInitiateTransaction(USBPB *pb);
  106.  
  107. OSErr            CFMInitialization( CFragInitBlock *initBlock );
  108.  
  109. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  110.     Name:        HexString8
  111.  
  112.     Input Parameters:    
  113.         v                unsigned long value
  114.         
  115.     Output Parameters:
  116.         p                8 bytes: hex string representing value
  117.         
  118.     Description:
  119.  
  120.     Change History:
  121.         28 Feb 1998,    oja:        Original version.
  122. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  123. static void
  124. HexString8( unsigned long v, unsigned char *p )
  125. {
  126.     int    shift;
  127.     
  128.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  129.     {
  130.         char c = (v >> shift) & 0x0F;
  131.         *p++ = c + (c > 9? ('A'-10): '0');
  132.     }
  133. }
  134.  
  135. #if DEBUG
  136. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  137.     Name:        hexstr
  138.  
  139.     Input Parameters:    
  140.         count                number of bytes
  141.         p                    pointer to bytes
  142.         
  143.     Output Parameters:
  144.         q                    hex dump of data
  145.         
  146.     Description:
  147.  
  148.     Change History:
  149.         28 Jul 1998,    oja:        Original version.
  150. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  151. void
  152. hexstr( int count, char *p, char *q );
  153.  
  154. void
  155. hexstr( int count, char *p, char *q )
  156. {
  157.     char *s = p;
  158.     int i = count;
  159.     for ( ; count > 0; --count, ++p )
  160.     {
  161.         int hi, lo;
  162.         hi = (*p >> 4)& 0x0F;
  163.         lo = *p & 0x0F;
  164.         *q++ = '0';
  165.         *q++ = 'x';
  166.         *q++ = hi + (hi > 9? 'A' - 10: '0');
  167.         *q++ = lo + (lo > 9? 'A' - 10: '0');
  168.         *q++ = ' ';
  169.     }
  170.     for ( ; i > 0; --i, ++s )
  171.         *q++ = *s < ' ' || *s > 0x7E? '.': *s;
  172. }
  173. #endif
  174.  
  175. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  176.     Name:        cstrlen
  177.  
  178.     Input Parameters:    
  179.         p            pointer to c-string
  180.         
  181.     Output Parameters:
  182.         int        length of string
  183.  
  184.     Description:
  185.         A replacement for strlen, since we don't want to depend on the
  186.         c library (can cause vm double page faults)
  187.  
  188.     Change History:
  189.         17 Aug 1998,    oja:        Original version.
  190. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  191.  
  192. static int
  193. cstrlen( char *p )
  194. {
  195.     int result = 0;
  196.     
  197.     while ( *p++ != '\0' )
  198.         ++result;
  199.  
  200.     return result;
  201. }
  202.  
  203. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  204.     Name:        cstrcpy
  205.  
  206.     Input Parameters:    
  207.         src        pointer to source c-string
  208.         
  209.     Output Parameters:
  210.         dst        c-string copy of src string
  211.  
  212.     Description:
  213.         A replacement for strcpy, since we don't want to depend on the
  214.         c library (can cause vm double page faults)
  215.  
  216.     Change History:
  217.         17 Aug 1998,    oja:        Original version.
  218. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  219.  
  220. static void
  221. cstrcpy( char *dst, char *src )
  222. {
  223.     while ( (*dst++ = *src++) != 0 )
  224.         ;
  225. }
  226.  
  227. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  228.     Name:        cstrcat
  229.  
  230.     Input Parameters:    
  231.         src        pointer to source c-string
  232.         
  233.     Output Parameters:
  234.         dst        c-string copy of src string
  235.  
  236.     Description:
  237.         A replacement for strcpy, since we don't want to depend on the
  238.         c library (can cause vm double page faults)
  239.  
  240.     Change History:
  241.         17 Aug 1998,    oja:        Original version.
  242. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  243.  
  244. static void
  245. cstrcat( char *dst, char *src )
  246. {
  247.     dst += cstrlen( dst );        // skip to end of the existing string
  248.     while ( (*dst++ = *src++) != 0 )
  249.         ;
  250. }
  251.  
  252. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  253.     Name:        USBStatusStr
  254.  
  255.     Input Parameters:    
  256.         usbStatus            usb error code
  257.         kind                    kPString or kCString
  258.         
  259.     Output Parameters:
  260.         unsigned char *    description of error (c-string or p-string)
  261.  
  262.     Description:
  263.         a simple mapping of errors to human-readable form
  264.  
  265.     Change History:
  266.         24 Apr 1998,    oja:        param to HexString8 was off-by-one
  267.         26 Mar 1998,    oja:        added kStrPrintClass to catenated strings
  268.         28 Feb 1998,    oja:        Original version.
  269. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  270. static unsigned char *
  271. USBStatusStr( OSStatus usbStatus, int kind )
  272. {
  273.     unsigned char *p;
  274.  
  275.     switch ( usbStatus )
  276.     {
  277.         case    kUSBInternalErr:                    p = "\p" kStrPrinterClass "Internal error"; break;
  278.         case    kUSBUnknownDeviceErr:            p = "\p" kStrPrinterClass "Unknown device"; break;
  279.         case    kUSBUnknownPipeErr:                 p = "\p" kStrPrinterClass "Unknown pipe"; break;
  280.         case    kUSBTooManyPipesErr:                p = "\p" kStrPrinterClass "Too many pipes"; break;
  281.         case    kUSBIncorrectTypeErr:            p = "\p" kStrPrinterClass "Incorrect type"; break;
  282.         case    kUSBRqErr:                            p = "\p" kStrPrinterClass "Request error"; break;
  283.         case    kUSBUnknownRequestErr:            p = "\p" kStrPrinterClass "Unknown request"; break;
  284.         case    kUSBTooManyTransactionsErr:    p = "\p" kStrPrinterClass "Too many transactions"; break;
  285.         case    kUSBAlreadyOpenErr:                p = "\p" kStrPrinterClass "Already open"; break;
  286.         case    kUSBNoDeviceErr:                    p = "\p" kStrPrinterClass "No device"; break;
  287.         case    kUSBDeviceErr:                        p = "\p" kStrPrinterClass "Device error"; break;
  288.         case    kUSBOutOfMemoryErr:                p = "\p" kStrPrinterClass "Out of memory"; break;
  289.         case    kUSBNotFound:                        p = "\p" kStrPrinterClass "Not found"; break;
  290.         case    kUSBLinkErr:                        p = "\p" kStrPrinterClass "Link Err"; break;
  291.         case    kUSBCRCErr:                            p = "\p" kStrPrinterClass "Comms/Device err, bad CRC";  break;        
  292.         case    kUSBBitstufErr:                    p = "\p" kStrPrinterClass "Comms/Device err, bitstuffing"; break;        
  293.         case    kUSBDataToggleErr:                p = "\p" kStrPrinterClass "Comms/Device err, Bad data toggle"; break;        
  294.         case    kUSBEndpointStallErr:            p = "\p" kStrPrinterClass "Device didn't understand"; break;        
  295.         case    kUSBNotRespondingErr:            p = "\p" kStrPrinterClass "No device, device hung"; break;        
  296.         case    kUSBPIDCheckErr:                    p = "\p" kStrPrinterClass "Comms/Device err, PID CRC error"; break;        
  297.         case    kUSBWrongPIDErr:                    p = "\p" kStrPrinterClass "Comms/Device err, Bad or wrong PID"; break;        
  298.         case    kUSBOverRunErr:                    p = "\p" kStrPrinterClass "Packet too large or more data than buffer"; break;        
  299.         case    kUSBUnderRunErr:                    p = "\p" kStrPrinterClass "Less data than buffer"; break;        
  300.         case    kUSBRes1Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  301.         case    kUSBRes2Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  302.         case    kUSBBufOvrRunErr:                    p = "\p" kStrPrinterClass "Buffer over run error"; break;        
  303.         case    kUSBBufUnderRunErr:                p = "\p" kStrPrinterClass "Buffer under run error"; break;        
  304.         case    kUSBNotSent1Err:                    p = "\p" kStrPrinterClass "Transaction not sent1"; break;        
  305.         case    kUSBNotSent2Err:                    p = "\p" kStrPrinterClass "Transaction not sent2"; break;    
  306.         default:
  307.             p = "\p" kStrPrinterClass "Unknown error nnnnnnnn";
  308.             HexString8( usbStatus, p + *p - 8 + 1 );
  309.             break;
  310.     }
  311.     
  312.     return kind == kPString? p: p + 1;
  313. }
  314.  
  315. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  316.     Name:        StateStr
  317.  
  318.     Input Parameters:    
  319.         usbRefCon            usb error code
  320.         kind                    kPString or kCString
  321.         
  322.     Output Parameters:
  323.         unsigned char *    description of state (c-string or p-string)
  324.  
  325.     Description:
  326.         a simple mapping of states to human-readable form
  327.  
  328.     Change History:
  329.         24 Apr 1998,    oja:        param to HexString8 was off-by-one
  330.         26 Mar 1998,    oja:        added kStrPrintClass to catenated strings
  331.         28 Feb 1998,    oja:        Original version.
  332. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  333. static unsigned char *
  334. StateStr( OSStatus refCon, int kind )
  335. {
  336.     unsigned char *p;
  337.  
  338.     refCon &= ~(kTransactionPending | kRetryTransaction | kReturnFromDriver);
  339.     switch ( refCon )
  340.     {
  341.         case kGetCapabilityString:                    p = "\p" kStrPrinterClass "kGetCapabilityString"; break;
  342.         case kDelayGetCapability:                    p = "\p" kStrPrinterClass "kDelayGetCapability"; break;
  343.         case kFindBulkOutPipe:                        p = "\p" kStrPrinterClass "kFindBulkOutPipe"; break;
  344.         case kFindBulkInPipe:                        p = "\p" kStrPrinterClass "kFindBulkInPipe"; break;
  345.         case kTaskTimeRequired:                        p = "\p" kStrPrinterClass "kTaskTimeRequired"; break;
  346.         default:
  347.             p = "\p" kStrPrinterClass "Unknown state nnnnnnnn";
  348.             HexString8( refCon, p + *p - 8 + 1 );
  349.             break;
  350.     }
  351.     return kind == kPString? p: p + 1;    
  352. }
  353.  
  354. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  355.     Name:        HiHex
  356.  
  357.     Input Parameters:    
  358.         v                        only low byte used
  359.         
  360.     Output Parameters:
  361.         <function result>    high nibble represented as ASCII char
  362.         
  363.     Description:
  364.  
  365.     Change History:
  366.         20 Mar 1998,    oja:        Original version.
  367. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  368. static unsigned char
  369. HiHex( int v )
  370. {
  371.     unsigned char    hinibble = (v >> 4) & 0x0f;
  372.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  373. }
  374.  
  375. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  376.     Name:        LoHex
  377.  
  378.     Input Parameters:    
  379.         v                        only low byte used
  380.         
  381.     Output Parameters:
  382.         <function result>    low nibble represented as ASCII char
  383.         
  384.     Description:
  385.  
  386.     Change History:
  387.         20 Mar 1998,    oja:        Original version.
  388. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  389. static unsigned char
  390. LoHex( int v )
  391. {
  392.     unsigned char    lonibble = v & 0x0f;
  393.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  394. }
  395.  
  396. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  397.     Name:        immediateError
  398.  
  399.     Input Parameters:    
  400.         
  401.     Output Parameters:
  402.         
  403.     Description:
  404.  
  405.     Change History:
  406.         28 Feb 1998,    oja:        Original version.
  407. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  408. static Boolean
  409. immediateError(OSStatus err)
  410. {
  411.     return((err != kUSBPending) && (err != noErr) );
  412. }
  413.  
  414. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  415.     Name:        SetNullUSBParamBlock
  416.  
  417.     Input Parameters:    
  418.         pb                    pointer to USB parameter block
  419.         dev                USB device reference
  420.     Output Parameters:
  421.         pb                    all fields set to default values
  422.  
  423.     Description:
  424.         setup a USB parameter block for use by the current device
  425.  
  426.     Change History:
  427.          8 Jun 1998,    oja:        modified for new param blocks
  428.         28 Feb 1998,    oja:        Original version.
  429. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  430. static void
  431. SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb )
  432. {
  433.     pb->qlink = NULL;
  434.     pb->qType = 0;
  435.     pb->pbLength = sizeof(USBPB);
  436.     pb->pbVersion = kUSBCurrentPBVersion;
  437.     pb->usbFlags = 0;
  438.     pb->usbStatus = noErr;
  439.     pb->usbCompletion = (USBCompletion) NULL;
  440.  
  441.     pb->usbReference = dev;
  442. }
  443.  
  444.  
  445. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  446.     Name:        ParseCapability
  447.  
  448.     Input Parameters:    
  449.         capability            pointer to 1284-1994 capability string
  450.         attribute            pointer to c-string key we're retrieving (terminate with colon)
  451.         *result_length        maximum length of the result 
  452.         
  453.     Output Parameters:
  454.         result                c-string which followed the key and was terminated by semi-colon
  455.                                 (semi-colon has been stripped)
  456.         *result_length        actual length of the result (may be zero)
  457.     
  458.     Description:
  459.         Search for "attribute" in the 1284 "capability" string
  460.         The identifier is terminated with a semi-colon
  461.  
  462.         Return the attribute in result
  463.             null-string if attribute not found.
  464.  
  465.     Change History:
  466.         20 Jul 1998,    oja:        fix computation of target_length
  467.         28 Feb 1998,    oja:        Original version.
  468. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  469. static void
  470. ParseCapability(
  471.     unsigned char    *capability,
  472.     unsigned char    *attribute,
  473.     unsigned char    *result,
  474.     int                *result_length 
  475. )
  476. {
  477.     //
  478.     //    search for "attribute" in the 1284 "capability" string
  479.     //
  480.     //    the identifier is terminated with a semi-colon
  481.     //
  482.     //    return the attribute in result
  483.     //            null-string if attribute not found
  484.     //
  485.     //    <to do> skip blanks, isolate colon, skip blanks
  486.     //
  487.     int                source_length,
  488.                         target_length;
  489.     unsigned char    *source,
  490.                         *target,
  491.                         *destination;
  492.     //
  493.     //    begin a brute force search
  494.     //
  495.     source = attribute;
  496.     source_length = cstrlen((char *)attribute );
  497.  
  498.     target = capability + 2;    // skip the length
  499.     target_length =  capability[1] | (capability[0] << 8);
  500.     target_length -= 2;            // don't count the length
  501.     while ( target_length >= source_length )
  502.     {
  503.         if ( memcmp( source, target, source_length ) == 0 )
  504.             break;
  505.         --target_length;
  506.         ++target;
  507.     }
  508.  
  509.     destination = result;
  510.     *destination = 0;    // empty result
  511.  
  512.     target += source_length;
  513.     target_length -= source_length;    // skip the attribute string
  514.  
  515.     if ( target_length > 0 )
  516.     {
  517.         //
  518.         //    we found the attribute in the capability string
  519.         //
  520.         while ( destination - result < *result_length )    // arbitrarily limit reply
  521.         {
  522.             if ( *target == ';' )
  523.                 break;
  524.             *destination++ = *target++;        // copy a byte of attribute over
  525.         }
  526.         *destination++ = '\0';                        // trailing NUL
  527.         *result_length = destination - result;    // report the length of the data (with trailing NUL)
  528.     }
  529. }
  530.  
  531.  
  532. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  533.     Name:        GetClass
  534.  
  535.     Input Parameters:    
  536.         capability            pointer to 1284-1994 capability string
  537.         *result_length        maximum length of the result 
  538.         
  539.     Output Parameters:
  540.         result                c-string extracted from the MODEL key
  541.         *result_length        actual length of the result  (may be zero)
  542.         
  543.     Description:
  544.         CLASS is a Microsoft extension to the 1284-capability string
  545.         if we don't find it
  546.             we assume that the device is a printer
  547.         Since the USB hardware has already indicated this, we're really allowing
  548.         devices which aren't printers to be reached via the DRVRs we've installed.
  549.  
  550.     Change History:
  551.         26 Mar 1998,    oja:        result_length is output too
  552.         28 Feb 1998,    oja:        Original version.
  553. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  554. static void
  555. GetClass(
  556.     unsigned char    *capability,
  557.     unsigned char    *result,
  558.     int                *result_length
  559. )
  560. {
  561. UInt32    i;
  562.     //
  563.     //    We supply the upper-case PRINTER to be consistent with 1284-1994
  564.     //        if we don't find a class.
  565.     //
  566.     ParseCapability( capability, (unsigned char *) "CLASS:", result, result_length);
  567.     if ( *result == '\0' )
  568.         ParseCapability( capability, (unsigned char *) "CLS:", result, result_length);
  569.     if ( *result == '\0' )
  570.         cstrcpy( (char *)result, "PRINTER" );
  571.     while (result[i])
  572.     {
  573.         result[i] &= 0x7f;
  574.         if (result[i] > 0x6f)
  575.             result[i] -= (unsigned char)('a' - 'A');
  576.         i++;
  577.     }
  578. }
  579.  
  580.  
  581. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  582.     Name:        GetModel
  583.  
  584.     Input Parameters:    
  585.         capability            pointer to 1284-1994 capability string
  586.         *result_length        maximum length of the result 
  587.         
  588.     Output Parameters:
  589.         result                c-string extracted from the MODEL key
  590.         *result_length        actual length of the result  (may be zero)
  591.             
  592.     Description:
  593.         MODEL is a required field of the 1284-capability string
  594.         MODEL may be abbreviated MDL
  595.  
  596.     Change History:
  597.         26 Mar 1998,    oja:        result_length is output too
  598.         28 Feb 1998,    oja:        Original version.
  599. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  600. static void
  601. GetModel(
  602.     unsigned char    *capability, 
  603.     unsigned char    *result,
  604.     int                *result_length
  605. )
  606. {
  607.     //
  608.     //    Most manufacturers abbreviate, so we search for MDL first
  609.     //
  610.     ParseCapability( capability, (unsigned char *) "MDL:", result, result_length );
  611.     if ( *result == '\0' )
  612.         ParseCapability( capability, (unsigned char *) "MODEL:", result, result_length );
  613. }
  614.  
  615.  
  616. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  617.     Name:        GetCommandSet
  618.  
  619.     Input Parameters:    
  620.         
  621.     Output Parameters:
  622.         
  623.     Description:
  624.  
  625.     Change History:
  626.         11 Nov 1998,    oja:        look for COMMAND SET not COMMAND-SET
  627.         28 Feb 1998,    oja:        Original version.
  628. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  629. static void
  630. GetCommandSet(
  631.     unsigned char *capability, 
  632.     unsigned char *result,
  633.     int *result_length
  634. )
  635. {
  636.     //
  637.     //    COMMAND-SET is a required field of the 1284-capability string
  638.     //    COMMAND-SET may be abbreviated CMD
  639.     //
  640.     ParseCapability( capability, (unsigned char *) "CMD:", result, result_length );
  641.     if ( *result == '\0' )
  642.         ParseCapability( capability, (unsigned char *) "COMMAND SET:", result, result_length );
  643. }
  644.  
  645. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  646.     Name:        GetManufacturer
  647.  
  648.     Input Parameters:    
  649.         
  650.     Output Parameters:
  651.         
  652.     Description:
  653.  
  654.     Change History:
  655.         26 Jun 1998,    oja:        Original version.
  656. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  657. static void
  658. GetManufacturer(
  659.     unsigned char *capability, 
  660.     unsigned char *result,
  661.     int *result_length
  662. )
  663. {
  664.     //
  665.     //    MANUFACTURER is a required field of the 1284-capability string
  666.     //    MANUFACTURER may be abbreviated MFG
  667.     //
  668.     ParseCapability( capability, (unsigned char *) "MFG:", result, result_length );
  669.     if ( *result == '\0' )
  670.         ParseCapability( capability, (unsigned char *) "MANUFACTURER:", result, result_length );
  671. }
  672.  
  673.  
  674. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  675.     Name:        DeregisterDevice
  676.  
  677.     Input Parameters:    
  678.         pPrinterPB
  679.  
  680.     Output Parameters:
  681.         <none>
  682.         
  683.     Description:
  684.         remove the device from the name registry
  685.  
  686.     Change History:
  687.         11 Jun 1998,    oja:        test from RegistryCStrEntryLookup was wrong direction
  688.         17 Apr 1998,    oja:        Original version.
  689. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  690. static OSStatus
  691. DeregisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  692. {
  693.     OSStatus        err;
  694.     RegEntryID    self;
  695.  
  696.     RegistryEntryIDInit( &self );
  697.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  698.     if ( err == noErr )
  699.     {
  700.         err = RegistryEntryDelete( &self);
  701.     }
  702.     RegistryEntryIDDispose(&self);
  703.     if (err == noErr &&  pPrinterPB->outRefNum != -1 )
  704.         err = TradRemoveDriver( pPrinterPB->outRefNum, false );
  705.     if (err == noErr &&  pPrinterPB->inRefNum != -1 )
  706.         err = TradRemoveDriver( pPrinterPB->inRefNum, false );
  707.     
  708.     return err;
  709. }
  710.  
  711. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  712.     Name:        RegisterDevice
  713.  
  714.     Input Parameters:    
  715.         pPrinterPB
  716.  
  717.     Output Parameters:
  718.         <none>
  719.         
  720.     Description:
  721.         add the device into the name registry; we can't insert just the node
  722.         if the parent nodes aren't present.
  723.  
  724.         if it isn't present
  725.             insert the device CLASS into the registry
  726.         if it isn't present
  727.             insert the device MODEL into the registry
  728.         finally insert the device itself into the registry
  729.             we're careful to rename multiple devices
  730.  
  731.     Change History:
  732.         16 Nov 1998,    oja:        better support for attributes which aren't in string
  733.         16 Jul 1998,    oja:        fix params to sprintf
  734.          8 Jun 1998,    oja:        don't use register param (CW build)
  735.         26 Mar 1998,    oja:        only register significant part of drvrNames 
  736.                                         log null model name to Expert
  737.                                         register command set 
  738.         28 Feb 1998,    oja:        Original version.
  739. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  740. static OSStatus
  741. RegisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  742. {
  743.     //
  744.     //    add the device into the name registry
  745.     //    if it isn't present
  746.     //        insert the device CLASS into the registry
  747.     //    if it isn't present
  748.     //        insert the device MODEL into the registry
  749.     //    finally insert the device itself into the registry
  750.     //        we're careful to rename multiple devices
  751.     //
  752.     Str255        identification,
  753.                     devclass,
  754.                     model,
  755.                     commands,
  756.                     tempstr;
  757.     RegEntryID    parent, where, self;
  758.     OSStatus        err;
  759.     int            model_length,
  760.                     command_length,
  761.                     class_length;
  762.  
  763.     class_length = sizeof(devclass);
  764.     GetClass( pPrinterPB->pCapabilityString, devclass, &class_length );
  765.  
  766.     command_length = sizeof(commands);
  767.     GetCommandSet(pPrinterPB->pCapabilityString, commands, &command_length );
  768.  
  769.     cstrcpy( (char *)pPrinterPB->name, (char *)"Devices:device-tree:" );
  770.     cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  771.     
  772.     RegistryEntryIDInit( &where );
  773.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name, &where );
  774.     if ( err == nrPathNotFound ) 
  775.     {
  776.         //    class not in registry
  777.         //        create a node for all devices of this CLASS
  778.         //
  779.         RegistryEntryIDInit( &parent );
  780.         err = RegistryCStrEntryLookup( nil, "Devices:device-tree:" , &parent );
  781.         if ( err == noErr )
  782.             err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &where );
  783.         RegistryEntryIDDispose(&parent);
  784.  
  785.     }
  786.     //
  787.     //    add this model into the name registry of this class
  788.     //
  789.     if ( err == noErr )
  790.     {
  791.         model_length = sizeof(model);
  792.         GetModel( pPrinterPB->pCapabilityString, model, &model_length );
  793.         if ( *model != '\0' )
  794.         {
  795.             cstrcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  796.             cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  797.             cstrcat( (char *)pPrinterPB->name, ":" );
  798.             cstrcat( (char *)pPrinterPB->name, (char *)model );
  799.             RegistryEntryIDInit( &self );
  800.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  801.             if ( err != noErr )
  802.             {
  803.                 // model not in registry
  804.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  805.             }
  806.             RegistryEntryIDDispose(&self);
  807.         }
  808.     }
  809.     //
  810.     //    add this instance of this model of this class
  811.     //        into the name registry
  812.     //
  813.     if ( *model == '\0'  )
  814.     {
  815.         //
  816.         //    possibly the cable isn't firmly connected or the printer isn't switched on
  817.         //
  818.         err = kUSBInternalErr;
  819.         USBExpertFatalError(pPrinterPB->deviceRef, err, "\p"kStrPrinterClass "\pModel undefined", 0);
  820.     }
  821.     if ( err == noErr )
  822.     {
  823.         //
  824.         //    start off by identifying the device simply by the model name
  825.         //        increment the numeric suffix until we successfully registry the device
  826.         //
  827.         Str32    suffix;
  828.         int    numeric_suffix;
  829.  
  830.         cstrcpy( (char *)identification, (char *)model );
  831.         RegistryEntryIDInit( &self );
  832.         for ( numeric_suffix = 1; numeric_suffix < MAX_SUFFIX; ++numeric_suffix )
  833.         {
  834.             cstrcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  835.             cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  836.             cstrcat( (char *)pPrinterPB->name, ":" );
  837.             cstrcat( (char *)pPrinterPB->name, (char *)model );
  838.             cstrcat( (char *)pPrinterPB->name, ":" );
  839.             cstrcat( (char *)pPrinterPB->name, (char *)identification );
  840.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  841.             if ( err != noErr )
  842.             {
  843.                 // enter device in registry
  844.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  845.                 if ( err == noErr )
  846.                     err = RegistryPropertyCreate( &self, "drvrOut", &pPrinterPB->driverOutName, 1 + pPrinterPB->driverOutName[0] );
  847.                 if ( err == noErr )
  848.                     err = RegistryPropertyCreate( &self, "outRef", &pPrinterPB->outRefNum, sizeof(pPrinterPB->outRefNum) );
  849.                 if ( err == noErr )
  850.                     err = RegistryPropertyCreate( &self, "drvrIn", &pPrinterPB->driverInName, 1 + pPrinterPB->driverInName[0] );
  851.                 if ( err == noErr )
  852.                     err = RegistryPropertyCreate( &self, "inRef", &pPrinterPB->inRefNum, sizeof(pPrinterPB->inRefNum) );
  853.                 if ( err == noErr )
  854.                     err = RegistryPropertyCreate( &self, "privateData", &pPrinterPB, sizeof(pPrinterPB) );
  855.                 if ( err == noErr )
  856.                     err = RegistryPropertyCreate( &self, "read", &pPrinterPB->r, sizeof(QueueUSBReadUPP) );
  857.                 if ( err == noErr )
  858.                     err = RegistryPropertyCreate( &self, "write", &pPrinterPB->w, sizeof(QueueUSBWriteUPP) );
  859.                 if ( err == noErr && *commands != '\0' )
  860.                     err = RegistryPropertyCreate( &self, "command-set", &commands, command_length );
  861.                 break;
  862.             }
  863.             //
  864.             //    if this name didn't succeed
  865.             //        try the next numeric suffix
  866.             //
  867.             sprintf( (char *)suffix, " %d", numeric_suffix );
  868.             cstrcpy( (char *)identification, (char *)model );
  869.             cstrcat( (char *)identification, (char *)suffix );
  870.         }
  871.         RegistryEntryIDDispose(&self);
  872.     }
  873.     
  874.     CStrToPStr((unsigned char *)tempstr, (char const *)pPrinterPB->name );
  875.     
  876.     USBExpertStatus( pPrinterPB->deviceRef, "\p" kStrPrinterClass "Added printer to name registry", 0 );
  877.     USBExpertStatus( pPrinterPB->deviceRef, tempstr, err );
  878.     RegistryEntryIDDispose(&where);
  879.  
  880.     LOGGING( logfile = fopen( "USBPrinter.log", "wb+" ) );
  881.     return err;
  882. }
  883.  
  884. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  885.     Name:        LoadResources
  886.  
  887.     Input Parameters:
  888.         pPrinterPB            pointer to class driver's private storage
  889.         
  890.     Output Parameters:
  891.         OSStatus                resource load error
  892.         
  893.     Description:
  894.         Initialize time is the only safe time to to load resources from our file.
  895.         Here's where we load resources and detach them from the resource manager.
  896.         Later we'll use these private copies instead of GetResource calls.
  897.         
  898.         Using the file spec that we got from the CFMInitialization routine, open
  899.         our resource fork.
  900.  
  901.     Change History:
  902.         11 Jun 1998,    oja:        removed hardcoded filename, use printerClassDriverFileSpec
  903.         20 Mar 1998,    oja:        Original version.
  904. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  905. static OSStatus
  906. LoadResources( struct usbPrinterPBStruct *pPrinterPB )
  907. {
  908.     short            rf = -1;                // class driver resource fork
  909.     OSStatus        err;
  910.  
  911.     //
  912.     //    open the resource fork of this class driver
  913.     //
  914.     rf = FSpOpenResFile( &printerClassDriverFileSpec,fsRdPerm );
  915.     err = ResError();
  916.     
  917.     //
  918.     //    load the DRVR that we'll stick in the unit table
  919.     //
  920.     pPrinterPB->hDrvr = NULL;
  921.     if ( err == noErr )
  922.     {
  923.         pPrinterPB->hDrvr = (DRVRHeaderHandle) Get1Resource( 'DRVR',  kUSBParallelDrvrRsrcID );
  924.         if ( pPrinterPB->hDrvr != NULL )
  925.             DetachResource( (Handle) pPrinterPB->hDrvr );
  926.         err = ResError();
  927.     }
  928.     
  929.     if ( rf != -1 )
  930.         CloseResFile( rf );
  931.     
  932.     return err;
  933. }
  934.  
  935. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  936.     Name:        InstallDrivers
  937.  
  938.     Input Parameters:
  939.         pPrinterPB
  940.         
  941.     Output Parameters:
  942.         OSStatus            error code
  943.         
  944.     Description:
  945.         install read and write drivers in the unit table
  946.             we have separate drivers so that we can support a full-duplex protocol
  947.         rename the driver we just installed (so multiple copies don't conflict)
  948.         We use the DRVR -refnum-1 so that the driver name has the same hex chars
  949.             as the driver number (for manual verification in MacsBug)
  950.  
  951.     Change History:
  952.         13 Jul 1998,    oja:        init err to noErr
  953.         26 Mar 1998,    oja:        Use refnum -1, use infix location to enumerate
  954.                                         DRVR
  955.         28 Feb 1998,    oja:        Original version.
  956. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  957. static OSStatus
  958. InstallDrivers( struct usbPrinterPBStruct *pPrinterPB )
  959. {
  960.     //
  961.     //    install the driver in the unit table
  962.     //    rename the driver we just installed (so multiple copies don't conflict)
  963.     //    
  964.     short            refNum;                // DRVR refNum
  965.     OSStatus        err =  paramErr;    // couldn't find driver
  966.  
  967.     if ( pPrinterPB->hDrvr != NULL )
  968.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->outRefNum );
  969.  
  970.     if ( err == noErr )
  971.     {
  972.         UnitNumber        unit;
  973.         DriverFlags        flags;
  974.         DRVRHeaderPtr    hdr;
  975.         unsigned char    *suffix,        // append "In" and "Out"
  976.                             *infix;        // driver reference number follows the ".USB"
  977.  
  978.         TradGetDriverInformation( pPrinterPB->outRefNum, &unit, &flags, pPrinterPB->driverOutName, &hdr );
  979.         BlockMove( pPrinterPB->driverOutName, pPrinterPB->driverInName, 1 + pPrinterPB->driverOutName[0] );
  980.         
  981.         suffix = pPrinterPB->driverOutName + pPrinterPB->driverOutName[0] - 2;
  982.         infix = pPrinterPB->driverOutName + kDrvrFirstDigit;
  983.         infix[0] = HiHex( -pPrinterPB->outRefNum -1 );
  984.         infix[1] = LoHex( -pPrinterPB->outRefNum -1 );
  985.         suffix[0] = 'O';
  986.         suffix[1] = 'u';
  987.         suffix[2] = 't';
  988.         TradRenameDriver( pPrinterPB->outRefNum, pPrinterPB->driverOutName );
  989.         //
  990.         //    set the driver data to point to our parameter block
  991.         //
  992.         err = OpenDriver( pPrinterPB->driverOutName, &refNum );
  993.         if ( err == noErr )
  994.         {
  995.             struct usbPrinterPBStruct *param = pPrinterPB;
  996.             err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  997.             CloseDriver( refNum );
  998.         }
  999.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->inRefNum );
  1000.         if ( err == noErr )
  1001.         {
  1002.             
  1003.             suffix = pPrinterPB->driverInName + pPrinterPB->driverInName[0] - 1;
  1004.             infix = pPrinterPB->driverInName + kDrvrFirstDigit;
  1005.             infix[0] = HiHex( -pPrinterPB->inRefNum -1 );
  1006.             infix[1] = LoHex( -pPrinterPB->inRefNum -1 );
  1007.             suffix[0] = 'I';
  1008.             suffix[1] = 'n';
  1009.             TradRenameDriver( pPrinterPB->inRefNum, pPrinterPB->driverInName );
  1010.             //
  1011.             //    set the driver data to point to our parameter block
  1012.             //
  1013.             err = OpenDriver( pPrinterPB->driverInName, &refNum );
  1014.             if ( err == noErr )
  1015.             {
  1016.                 struct usbPrinterPBStruct *param = pPrinterPB;
  1017.                 err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1018.                 CloseDriver( refNum );
  1019.             }
  1020.         }
  1021.     }
  1022.  
  1023.     return err;
  1024. }
  1025.  
  1026. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1027.     Name:        GetCapability
  1028.  
  1029.     Input Parameters:    
  1030.         
  1031.     Output Parameters:
  1032.         
  1033.     Description:
  1034.         Asynchronous completion.
  1035.  
  1036.     Change History:
  1037.         28 Feb 1998,    oja:        Original version.
  1038. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1039. static void
  1040. GetCapability( struct usbPrinterPBStruct *pPrinterPB, unsigned char *p, int length )
  1041. {
  1042.     //
  1043.     //    queue a transaction to retrieve the 1284 capability string
  1044.     //        we must have assigned the interface by this point since the capability string
  1045.     //        may vary with the interface
  1046.     //
  1047.     OSStatus        err;
  1048.     USBPB            *pb = &pPrinterPB->pb;
  1049.     
  1050.     SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  1051.     
  1052.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1053.     pb->usbBuffer = 0;
  1054.     pb->usbActCount = 0;
  1055.     pb->usbReqCount = 0;
  1056.  
  1057.     pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
  1058.     pb->usb.cntl.WValue = pPrinterPB->configurationNumber;            // configuration
  1059.     pb->usb.cntl.WIndex = (pPrinterPB->interfaceNumber<<8) | pPrinterPB->alternateSetting;
  1060.  
  1061.     pb->usbReqCount = length;
  1062.     pb->usbBuffer = p;
  1063.  
  1064.     pb->usbRefcon |= kTransactionPending;
  1065.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1066.     err = USBDeviceRequest(pb);
  1067.     if(immediateError(err))
  1068.     {
  1069.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetCapability", 0);
  1070.         pb->usbRefcon |= kReturnFromDriver;
  1071.     }
  1072. }
  1073.  
  1074. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1075.     Name:        IsLucentCable
  1076.  
  1077.     Input Parameters:    
  1078.         dev            USB device descriptor
  1079.         
  1080.     Output Parameters:
  1081.         Return 1 if the USB device is a USB-parallel cable
  1082.         
  1083.     Description:
  1084.         
  1085.  
  1086.     Change History:
  1087.         28 Feb 1998,    oja:        Original version.
  1088. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1089. static int
  1090. IsLucentCable( USBDeviceDescriptor    *dev )
  1091. {
  1092.     return ( USBToHostWord(dev->vendor) == 0x47E && USBToHostWord(dev->product) == 0x1001 )? 1: 0;
  1093. }
  1094.  
  1095.  
  1096. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1097.     Name:        GetInterface
  1098.  
  1099.     Input Parameters:    
  1100.         
  1101.     Output Parameters:
  1102.         
  1103.     Description:
  1104.         Asynchronous completion.
  1105.  
  1106.     Change History:
  1107.         28 Feb 1998,    oja:        Original version.
  1108. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1109. static void
  1110. GetInterface( USBPB *pb, UInt8 *alt )
  1111. {
  1112.     //
  1113.     //    make sure we account for any alternate interface currently in use by the device
  1114.     //
  1115.     OSStatus    err;
  1116.  
  1117.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
  1118.  
  1119.     pb->usb.cntl.BRequest = kUSBRqGetInterface;
  1120.     pb->usb.cntl.WValue = 0; 
  1121.     pb->usb.cntl.WIndex = 0;
  1122.  
  1123.     pb->usbReqCount = sizeof(UInt8);        // single byte is requested
  1124.     pb->usbBuffer = alt;
  1125.  
  1126.     pb->usbStatus = 0;
  1127.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1128.     pb->usbRefcon |= kTransactionPending;
  1129.  
  1130.     err = USBDeviceRequest(pb);
  1131.     if(immediateError(err))
  1132.     {
  1133.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetInterface", 0);
  1134.         pb->usbRefcon |= kReturnFromDriver;
  1135.     }
  1136. }
  1137.  
  1138.  
  1139. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1140.     Name:        ReadCompletion
  1141.  
  1142.     Input Parameters:    
  1143.         pb                        USB parameter block
  1144.         
  1145.     Output Parameters:
  1146.         <none>
  1147.  
  1148.     Description:
  1149.         USB read requests complete here.
  1150.         We dequeue the MacOS DRVR read requests
  1151.  
  1152.     Change History:
  1153.         10 Aug 1998,    oja:        set readDrvr.ctl to NULL when finished
  1154.         28 Jul 1998,    oja:        breakdown transactions into MAX_USB_TRANSFER_SIZE
  1155.         27 Jul 1998,    oja:        lock memory (UIM doesn't do this properly)
  1156.         20 Jul 1998,    oja:        retry transactions
  1157.          8 Jun 1998,    oja:        clear stalls on error
  1158.         28 Feb 1998,    oja:        Original version.
  1159. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1160. static void
  1161. ReadCompletion(USBPB *pb)
  1162. {
  1163.     //    call the user completion routine
  1164.     struct usbPrinterPBStruct
  1165.             *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1166.     IOParamPtr     clientParam = pPrinterPB->readDrvr.pb;
  1167.     OSStatus        err = pb->usbStatus;
  1168.     DCtlPtr            ctlLocal;
  1169.  
  1170. #if MACSBUG_ON_READ_COMPLETE
  1171.     Str255    text;
  1172.     sprintf( (char *)text, " PrinterClass Read Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1173.     text[0] = cstrlen((char *)text); // c2pstr
  1174.     DebugStr( text );
  1175. #endif
  1176.  
  1177. #if DOUBLE_BUFFER
  1178.     //
  1179.     //    copy the user data from our page aligned buffer
  1180.     //
  1181.     USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion - read  " , (UInt32)pb->usbActCount );
  1182.  
  1183.     if ( pb->usbActCount > 0 )
  1184.         BlockCopy( pPrinterPB->pageReadAlignedBuffer, clientParam->ioBuffer + clientParam->ioActCount, pb->usbActCount );
  1185. #endif
  1186.     //    update the amount of data actually transferred
  1187.     clientParam->ioActCount += pb->usbActCount;
  1188.  
  1189.     switch( pb->usbStatus )
  1190.     {
  1191.         //
  1192.         //    only retry low level hardware problems
  1193.         //        note: abort transactions will end up here as well
  1194.         //
  1195.     case kUSBLinkErr:
  1196.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1197.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1198.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1199.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1200.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1201.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1202.         if (  --(pPrinterPB->readRetryCount) > 0 ) 
  1203.         {
  1204.             // we got an error, and we still want to retry, clear any stalls
  1205.             USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion retry" , pb->usbStatus );
  1206.             USBClearPipeStallByReference(pPrinterPB->readPipeRef);
  1207.             pb->usbStatus = noErr;
  1208.         }
  1209.         break;
  1210.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1211.         USBClearPipeStallByReference(pPrinterPB->readPipeRef);
  1212.         USBClearPipeStallByReference(pPrinterPB->deviceRef);
  1213.         break;
  1214.         //
  1215.         //    any other error will be reported to the client
  1216.         //
  1217.     default:
  1218.     case noErr:
  1219.         break;
  1220.     }
  1221.     if ( pb->usbStatus == noErr &&                                     // there were no problems
  1222.         pb->usbActCount >= pb->usbReqCount &&                        // we got all the data we requested
  1223.         clientParam->ioActCount < clientParam->ioReqCount )    // we still want more data
  1224.     {
  1225.         //
  1226.         //    haven't finish the client's request
  1227.         //        update the pointers and start another bulk read transaction
  1228.         //
  1229. #if LOCK_MEMORY
  1230.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1231.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion UnlockMem failed" ) );
  1232. #endif
  1233.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1234.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1235. #if MAX_USB_TRANSFER_SIZE
  1236.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1237.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1238. #endif
  1239. #if DOUBLE_BUFFER
  1240.         //
  1241.         //    make sure we have enough room in our buffer
  1242.         //
  1243.         if ( pb->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1244.             pb->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1245.         pb->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1246. #endif
  1247. #if LOCK_MEMORY
  1248.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1249.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion LockMem failed" ) );
  1250.         if ( err == noErr )
  1251. #endif
  1252.             err = USBBulkRead( pb );
  1253.         if ( immediateError(err) )
  1254.         {
  1255.             USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion finish immed err" , err );
  1256.  
  1257.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1258.             if ( pPrinterPB->readDrvr.ctl != NULL )
  1259.             {
  1260.                 ctlLocal = pPrinterPB->readDrvr.ctl;
  1261.                 pPrinterPB->readDrvr.ctl = NULL;
  1262.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal ); 
  1263.             }
  1264.         }
  1265.     }
  1266.     else
  1267.     {
  1268.         //
  1269.         //        either we have an error which we're not retrying
  1270.         //            or we successfully completed
  1271.         //
  1272. #if LOCK_MEMORY
  1273.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1274.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion concluded UnlockMem failed" ) );
  1275. #endif
  1276.         IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion Error" , pb->usbStatus ) );
  1277.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1278.         USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "readDrvr.ctl = " , (UInt32)pPrinterPB->readDrvr.ctl );
  1279.         if ( pPrinterPB->readDrvr.ctl != NULL )
  1280.         {
  1281.             ctlLocal = pPrinterPB->readDrvr.ctl;
  1282.             pPrinterPB->readDrvr.ctl = NULL;
  1283.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal); 
  1284.         }
  1285.         else
  1286.         {
  1287.             IF_DEBUG( DebugStr( "\pReadCompletion() pPrinterPB->readDrvr.ctl == NULL" ) );
  1288.         }
  1289.     }
  1290. }
  1291.  
  1292.  
  1293. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1294.     Name:        WriteCompletion
  1295.  
  1296.     Input Parameters:    
  1297.         pb                        USB parameter block
  1298.         
  1299.     Output Parameters:
  1300.         <none>
  1301.  
  1302.     Description:
  1303.         USB write requests complete here.
  1304.         We dequeue the MacOS DRVR write requests
  1305.  
  1306.         when breaking up transactions we use ioActCount to determine how much remains 
  1307.                 of the original request and where the next request begins
  1308.         if we've failed with a USB error
  1309.             usbActCount indicates how much data has been transferred with the current request
  1310.             and if the retry count hasn't been exceeded
  1311.                 we proceed as if we'd just requested that much in this transactions
  1312.         note the retry count is cumulative for the original client request
  1313.             not for each usb transaction
  1314.  
  1315.     Change History:
  1316.         16 Nov 1998,    oja:        restored missing writeDrvr.ctl != NULL
  1317.          4 Nov 1998,    oja:        allow chaining of DRVR calls
  1318.         10 Aug 1998,    oja:        set writeDrvr.ctl to NULL when finished
  1319.         28 Jul 1998,    oja:        breakdown transactions into MAX_USB_TRANSFER_SIZE
  1320.         27 Jul 1998,    oja:        lock memory (UIM doesn't do this properly)
  1321.         20 Jul 1998,    oja:        retry transactions
  1322.         16 Jul 1998,    oja:        clear write pipe, not control pipe
  1323.         28 Feb 1998,    oja:        Original version.
  1324. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1325. static void
  1326. WriteCompletion(USBPB *pb)
  1327. {
  1328.     //    call the user completion routine
  1329.     struct usbPrinterPBStruct
  1330.                     *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1331.     IOParamPtr     clientParam = pPrinterPB->writeDrvr.pb;
  1332.     DCtlPtr            ctlLocal;
  1333.     OSStatus        err = pb->usbStatus;
  1334.  
  1335. #if MACSBUG_ON_WRITE_COMPLETE
  1336.     Str255    text;
  1337.     sprintf( (char *)text, " PrinterClass Write Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1338.     text[0] = cstrlen((char *)text); // c2pstr
  1339.     DebugStr( text );
  1340. #endif
  1341.  
  1342.     //    update the amount of data actually transferred
  1343.     clientParam->ioActCount += pb->usbActCount;
  1344.     USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion - wrote  " , (UInt32)pb->usbActCount );
  1345.  
  1346.     switch( pb->usbStatus )
  1347.     {
  1348.         //
  1349.         //    only retry low level hardware problems
  1350.         //        note: abort transactions will end up here as well
  1351.         //
  1352.     case kUSBLinkErr:
  1353.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1354.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1355.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1356.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1357.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1358.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1359.         if (  --(pPrinterPB->writeRetryCount) > 0 ) 
  1360.         {
  1361.             // we got an error, and we still want to retry, clear any stalls
  1362.             USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion retry" , pb->usbStatus );
  1363.             USBClearPipeStallByReference(pPrinterPB->writePipeRef);
  1364.             pb->usbStatus = noErr;
  1365.         }
  1366.         break;
  1367.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1368.         USBClearPipeStallByReference(pPrinterPB->writePipeRef);
  1369.         USBClearPipeStallByReference(pPrinterPB->deviceRef);
  1370.         break;
  1371.         //
  1372.         //    any other error will be reported to the client
  1373.         //
  1374.     default:
  1375.     case noErr:
  1376.         break;
  1377.     }
  1378.  
  1379.     if ( pb->usbStatus == noErr && clientParam->ioActCount < clientParam->ioReqCount )
  1380.     {
  1381.         //
  1382.         //    haven't finish the client's request
  1383.         //        update the pointers and start another bulkOut transaction
  1384.         //
  1385. #if LOCK_MEMORY
  1386.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1387.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion UnlockMem failed" ) );
  1388. #endif
  1389.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1390.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1391. #if MAX_USB_TRANSFER_SIZE
  1392.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1393.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1394. #endif
  1395. #if DOUBLE_BUFFER
  1396.         //
  1397.         //    make sure we have enough room in our buffer
  1398.         //    then copy the user data into our page aligned buffer
  1399.         //
  1400.         if ( pb->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1401.             pb->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1402.         BlockCopy( pb->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, pb->usbReqCount );
  1403.         pb->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1404. #endif
  1405. #if LOCK_MEMORY
  1406.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1407.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion LockMem failed" ) );
  1408.         if ( err == noErr )
  1409. #endif
  1410.             err = USBBulkWrite( pb );
  1411.         if ( immediateError(err) )
  1412.         {
  1413.             USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion finish immed err" , err );
  1414.  
  1415.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1416.             if ( pPrinterPB->writeDrvr.ctl != NULL )
  1417.             {
  1418.                 ctlLocal = pPrinterPB->writeDrvr.ctl;
  1419.                 pPrinterPB->writeDrvr.ctl = NULL;
  1420.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal ); 
  1421.             }
  1422.         }
  1423.     }
  1424.     else
  1425.     {
  1426.         //
  1427.         //        either we have an error which we're not retrying
  1428.         //            or we successfully completed
  1429.         //
  1430. #if LOCK_MEMORY
  1431.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1432.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion concluded UnlockMem failed" ) );
  1433. #endif
  1434.         IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion Error" , pb->usbStatus ) );
  1435.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1436.         USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "writeDrvr.ctl = " , (UInt32)pPrinterPB->writeDrvr.ctl );
  1437.         if ( pPrinterPB->writeDrvr.ctl != NULL )
  1438.         {
  1439.             ctlLocal = pPrinterPB->writeDrvr.ctl;
  1440.             pPrinterPB->writeDrvr.ctl = NULL;
  1441.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal ); 
  1442.         }
  1443.         else
  1444.         {
  1445.             IF_DEBUG( DebugStr( "\pWriteCompletion() pPrinterPB->writeDrvr.ctl == NULL" ) );
  1446.         }
  1447.     }
  1448. }
  1449.  
  1450. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1451.     Name:        QueueRead
  1452.  
  1453.     Input Parameters:    
  1454.         pb                        MacOS device manager parameter block
  1455.         ctl                    device manager dCtl block
  1456.         pPrinterPB            current printing device class's storage
  1457.         
  1458.     Output Parameters:
  1459.         <none>
  1460.  
  1461.     Description:
  1462.         MacOS DRVR read requests are re-queued here to the USB
  1463.         Since we only allow one read request pending at a time, we're able
  1464.         to use the USB refCon to point to our class driver's storage.
  1465.  
  1466.     Change History:
  1467.         16 Nov 1998,    oja:        added LOCKMEMORY
  1468.         28 Feb 1998,    oja:        Original version.
  1469. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1470. void
  1471. QueueRead( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1472. {    
  1473.     OSStatus    err;
  1474.     USBPB        *usbprint = &pPrinterPB->in;
  1475.     
  1476. #if MACSBUG_ON_READ
  1477.     Str255    text;
  1478.  
  1479.     sprintf( (char *)text, " PrinterClass Read: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1480.     text[0] = cstrlen((char *)text); // c2pstr
  1481.     USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
  1482. //    DebugStr( text );
  1483. #endif
  1484.  
  1485.     pb->ioActCount = 0;        // nothing transfered yet
  1486.     if ( pPrinterPB->terminating )
  1487.         pb->ioResult = abortErr;
  1488.     else
  1489.     {
  1490.  
  1491.         pPrinterPB->readRetryCount = 5;
  1492.         pPrinterPB->readDrvr.pb= pb;
  1493.         pPrinterPB->readDrvr.ctl = ctl;
  1494.         if (( pPrinterPB->readPipeRef != NULL ) && (pPrinterPB->printerConfigured))
  1495.         {
  1496.             SetNullUSBParamBlock( pPrinterPB->readPipeRef,  usbprint );
  1497.             USBExpertStatus(usbprint->usbReference, "\pSet up to do bulk read", pb->ioReqCount );
  1498.             usbprint->usbActCount = 0;
  1499.             usbprint->usbBuffer = pb->ioBuffer;
  1500.             usbprint->usbReqCount = pb->ioReqCount;
  1501.  
  1502. #if MAX_USB_TRANSFER_SIZE
  1503.             //
  1504.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1505.             //        or there is an error which can't be retried
  1506.             //
  1507.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1508.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1509. #endif
  1510. #if DOUBLE_BUFFER
  1511.             //
  1512.             //    make sure we have enough room in our buffer
  1513.             //    then copy the user data into our page aligned buffer
  1514.             //
  1515.             if ( usbprint->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1516.                 usbprint->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1517.             usbprint->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1518. #endif
  1519.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1520.             usbprint->usbCompletion = (USBCompletion) ReadCompletion;
  1521.             
  1522.             pb->ioResult = ioInProgress;
  1523. #if LOCK_MEMORY
  1524.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  1525.             IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueRead LockMem failed" ) );
  1526.             if ( err == noErr )
  1527. #endif
  1528.             err = USBBulkRead( usbprint );
  1529.             if ( immediateError(err) )
  1530.             {
  1531.                 USBExpertStatus(usbprint->usbReference, "\pError doing bulk read",0 );
  1532.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1533.                 pb->ioResult = err;
  1534.             }
  1535.         }
  1536.         else
  1537.         {
  1538.             USBExpertStatus(usbprint->usbReference, "\p" kStrPrinterClass "Read to unopened pipe" , usbprint->usbStatus ) ;
  1539.             pb->ioResult = abortErr;
  1540.         }
  1541.     }
  1542. }
  1543.  
  1544. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1545.     Name:        QueueWrite
  1546.  
  1547.     Input Parameters:    
  1548.         pb                        MacOS device manager parameter block
  1549.         ctl                    device manager dCtl block
  1550.         pPrinterPB            current printing device class's storage
  1551.         
  1552.     Output Parameters:
  1553.         <none>
  1554.  
  1555.     Description:
  1556.         MacOS DRVR write requests are re-queued here to the USB
  1557.         Since we only allow one read request pending at a time, we're able
  1558.         to use the USB refCon to point to our class driver's storage.
  1559.  
  1560.     Change History:
  1561.         28 Feb 1998,    oja:        Original version.
  1562. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1563. void
  1564. QueueWrite( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1565. {
  1566.     OSStatus    err;
  1567.     USBPB        *usbprint = &pPrinterPB->out;
  1568. #if VIRTUAL_MEMORY_CHECK
  1569.     //
  1570.     //    dump the VM table
  1571.     //
  1572.     Str255                        text;
  1573.     LogicalToPhysicalTable    *vmTable;
  1574.     MemoryBlock                    *physical;
  1575.     unsigned long                vmCount,
  1576.                                     vmEntry,
  1577.                                     vmTblLength;
  1578. #endif
  1579.  
  1580. #if MACSBUG_ON_WRITE
  1581.     Str255    text;
  1582.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1583.     text[0] = cstrlen((char *)text); // c2pstr
  1584.     USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
  1585. //    DebugStr( text );
  1586. #endif
  1587.  
  1588. #if VIRTUAL_MEMORY_CHECK
  1589.     //
  1590.     //    this check current won't compile without runtime error: need to lock memory, but lock has moved
  1591.     //
  1592.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1593.     text[0] = cstrlen((char *)text); // c2pstr
  1594.     USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
  1595.     
  1596.     vmCount = 127;
  1597.     vmTblLength = (vmCount+1)*sizeof(MemoryBlock);
  1598.     vmTable = (LogicalToPhysicalTable *) NewPtrSys( vmTblLength );
  1599.     LockMemory( vmTable, vmTblLength );
  1600.     LockMemory( &vmCount, sizeof(unsigned long) );
  1601.     vmTable->logical.address = pb->ioBuffer;
  1602.     vmTable->logical.count = pb->ioReqCount;
  1603.     err = GetPhysical( vmTable, &vmCount );
  1604.     
  1605.     if ( err == noErr )
  1606.     {
  1607.         for ( vmEntry = 0, physical = &vmTable->physical[0]; vmEntry < vmCount; ++vmEntry , ++physical)
  1608.         {
  1609.             sprintf( (char *)text, " PrinterClass Write: VM @%08x (%d)", physical->address, physical->count );
  1610.             text[0] = cstrlen((char *)text); // c2pstr
  1611.             USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
  1612.         }
  1613.     }
  1614.     UnlockMemory( vmTable, vmTblLength );
  1615.     UnlockMemory( &vmCount, sizeof(unsigned long) );
  1616. #endif
  1617.     pb->ioActCount = 0;        // nothing transfered yet
  1618.  
  1619.  
  1620.     usbprint->usbStatus = noErr;    // forget about abort and things from previous writes
  1621.     if ( pPrinterPB->terminating )
  1622.         pb->ioResult = abortErr;
  1623.     else
  1624.     {
  1625.         pPrinterPB->writeRetryCount = 5;
  1626.         pPrinterPB->writeDrvr.pb = pb;
  1627.         pPrinterPB->writeDrvr.ctl = ctl;
  1628.         if (( pPrinterPB->writePipeRef != NULL ) && (pPrinterPB->printerConfigured))
  1629.         {
  1630.             SetNullUSBParamBlock( pPrinterPB->writePipeRef,  usbprint );
  1631.             USBExpertStatus(usbprint->usbReference, "\pSet up to do bulk write", pb->ioReqCount );
  1632.             usbprint->usbActCount = 0;
  1633.             usbprint->usbBuffer = pb->ioBuffer;
  1634.             usbprint->usbReqCount = pb->ioReqCount;
  1635. #if MAX_USB_TRANSFER_SIZE
  1636.             //
  1637.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1638.             //        or there is an error which can't be retried
  1639.             //
  1640.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1641.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1642. #endif
  1643. #if DOUBLE_BUFFER
  1644.             //
  1645.             //    make sure we have enough room in our buffer
  1646.             //    then copy the user data into our page aligned buffer
  1647.             //
  1648.             if ( usbprint->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1649.                 usbprint->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1650.             BlockCopy( usbprint->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, usbprint->usbReqCount );
  1651.             usbprint->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1652. #endif
  1653.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1654.             usbprint->usbCompletion = (USBCompletion) WriteCompletion;
  1655.              
  1656.             pb->ioResult = ioInProgress;
  1657.     
  1658. #if LOCK_MEMORY
  1659.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  1660.             IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueWrite LockMem failed" ) );
  1661.             if ( err == noErr )
  1662. #endif
  1663.                 err = USBBulkWrite( usbprint );
  1664.             if ( immediateError(err) )
  1665.             {
  1666.                 USBExpertStatus(usbprint->usbReference, "\pError doing bulk write",0 );
  1667.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1668.                 pb->ioResult = err;
  1669.             }
  1670.             //
  1671.             //    note our logging is one write for each the client request
  1672.             //        not one write for each usb transaction
  1673.             //
  1674.             LOGGING( fwrite( pb->ioBuffer, sizeof(char), pb->ioReqCount, logfile ) );
  1675.         }
  1676.         else
  1677.         {
  1678.             USBExpertStatus(usbprint->usbReference, "\p" kStrPrinterClass "Write to unopened pipe" , usbprint->usbStatus );
  1679.             pb->ioResult = abortErr;
  1680.         }
  1681.     }
  1682. }
  1683.  
  1684.  
  1685. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1686.     Name:        Abort
  1687.  
  1688.     Input Parameters:    
  1689.         refNum            DRVR refnum
  1690.         pPrinterPB        current printing device class's storage
  1691.  
  1692.     Output Parameters:
  1693.         
  1694.     Description:
  1695.         Asynchronous completion.
  1696.         Note: USBAbortPipeByReference can leave the data toggle in the wrong state.
  1697.                 We need to abort both pipes, and then the client must soft reset the printer
  1698.                 to get the printer's data toggles correct.
  1699.         We prematurely call completion routines for active i/o so that CloseDriverSync
  1700.             will not hang the system after an abort, including hot unplug. This works out okay,
  1701.             since the request will be dequeued now, and when the i/o actually terminates
  1702.             the system will be called with an invalid queue element and then reject this second
  1703.             attempt to dequeue the i/o.
  1704.  
  1705.     Change History:
  1706.          4 Aug 1998,    oja:        abort both pipes, call completion routines
  1707.         28 Feb 1998,    oja:        Original version.
  1708. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1709. OSStatus
  1710. Abort( DriverRefNum refNum, struct usbPrinterPBStruct *pPrinterPB )
  1711. {
  1712.     OSStatus        err = noErr;
  1713.  
  1714.  
  1715.     refNum = 0;    // unused
  1716.     //
  1717.     //    if there's any pending io this will call the completion routine
  1718.     //
  1719.     err = USBAbortPipeByReference( pPrinterPB->writePipeRef );
  1720.     err = USBAbortPipeByReference( pPrinterPB->readPipeRef );
  1721.  
  1722.     if ( pPrinterPB->out.usbCompletion != (USBCompletion) NULL )
  1723.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->writeDrvr.pb, pPrinterPB->writeDrvr.ctl ); 
  1724.     if ( pPrinterPB->in.usbCompletion != (USBCompletion) NULL )
  1725.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->readDrvr.pb, pPrinterPB->readDrvr.ctl ); 
  1726.     return err;
  1727. }
  1728.  
  1729.  
  1730. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1731.     Name:        CompletionProc
  1732.  
  1733.     Input Parameters:    
  1734.         pb                    USB param block ptr
  1735.     
  1736.     Output Parameters:
  1737.         
  1738.     Description:
  1739.         Asynchronous completion routine for DRVR requests.
  1740.  
  1741.     Change History:
  1742.         10 Aug 1998,    oja:        if error, do not set clientParam's ioResult
  1743.                                             explicitly (wait for JIODone)
  1744.         11 Jun 1998,    oja:        Original version.
  1745. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1746. static void 
  1747. CompletionProc(USBPB *pb)
  1748. {
  1749.     //    call the user completion routine
  1750.     struct usbPrinterPBStruct
  1751.                     *pPrinterPB = (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1752.     IOParamPtr     clientParam = pPrinterPB->statusDrvr.pb;
  1753.  
  1754.     clientParam->ioActCount = pb->usbActCount;
  1755.  
  1756.     if ( pb->usbStatus != noErr ) 
  1757.     {
  1758.         USBClearPipeStallByReference(pb->usbReference);  // we got an error, try to clear any stalls
  1759.  
  1760.         IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass "CompletionProc Error" , pb->usbStatus ) );
  1761.         IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
  1762.     }
  1763.  
  1764.     pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1765.     if ( pPrinterPB->statusDrvr.ctl != NULL )
  1766.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->statusDrvr.ctl ); 
  1767. }
  1768.  
  1769. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1770.     Name:        CentronicsStatus
  1771.  
  1772.     Input Parameters:    
  1773.         pb                        MacOS device manager parameter block
  1774.         ctl                    device manager dCtl block
  1775.         pPrinterPB            current printing device class's storage
  1776.  
  1777.     Output Parameters:
  1778.         pStatusByte        
  1779.         
  1780.     Description:
  1781.         setup the device request for a USB printer class request one byte status.
  1782.  
  1783.     Change History:
  1784.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  1785.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  1786.         11 Jun 1998,    oja:        Original version.
  1787. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1788. static void
  1789. CentronicsStatus( USBPB *usbprint, Ptr buffer, short interfaceNumber )
  1790. {
  1791.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1792.  
  1793.     usbprint->usb.cntl.BRequest = kUSBPrintClassGetCentronicsStatus;
  1794.     usbprint->usb.cntl.WValue = 0;
  1795.     usbprint->usb.cntl.WIndex = interfaceNumber;
  1796.  
  1797.     usbprint->usbReqCount = 1;
  1798.     usbprint->usbBuffer = buffer;
  1799. }
  1800.  
  1801. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1802.     Name:        SoftReset
  1803.  
  1804.     Input Parameters:    
  1805.         usbprint                USB param block
  1806.         interfaceNumber
  1807.  
  1808.     Output Parameters:
  1809.         
  1810.     Description:
  1811.         Setup the device request for a USB printer class request soft reset.
  1812.  
  1813.     Change History:
  1814.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  1815.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  1816.         11 Jun 1998,    oja:        Original version.
  1817. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1818. void
  1819. SoftReset( USBPB *usbprint, short interfaceNumber )
  1820. {
  1821.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBOther);
  1822.  
  1823.     usbprint->usb.cntl.BRequest = kUSBPrintClassSoftReset;
  1824.     usbprint->usb.cntl.WValue = 0;
  1825.     usbprint->usb.cntl.WIndex = interfaceNumber;
  1826.  
  1827.     usbprint->usbReqCount = 0;
  1828.     usbprint->usbBuffer = NULL;
  1829.  
  1830. }
  1831.  
  1832. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1833.     Name:        CapabilityRequest
  1834.  
  1835.     Input Parameters:    
  1836.         usbprint            USB parameter block
  1837.         p                    result pointer
  1838.         length            amount of data allocated
  1839.         config
  1840.         interfaceNum
  1841.         alternateSetting
  1842.         
  1843.  
  1844.     Output Parameters:
  1845.         p                    result pointer
  1846.         length            amount of data allocated
  1847.         
  1848.     Description:
  1849.         setup the device request for a USB printer class request 1284 id string.
  1850.  
  1851.     Change History:
  1852.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  1853.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  1854.         11 Jun 1998,    oja:        Original version.
  1855. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1856. void
  1857. CapabilityRequest( USBPB *pb, Ptr p, long length, short configValue, short interfaceNumber, short alternateSetting  )
  1858. {
  1859.  
  1860.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1861.  
  1862.     pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
  1863.     pb->usb.cntl.WValue = configValue;        // configuration
  1864.     pb->usb.cntl.WIndex = (interfaceNumber<<8) | alternateSetting;
  1865.  
  1866.     pb->usbReqCount = length;
  1867.     pb->usbBuffer = p;
  1868.  
  1869. }
  1870.  
  1871. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1872.     Name:        StatusControlRequests
  1873.  
  1874.     Input Parameters:    
  1875.         pb                        MacOS device manager parameter block
  1876.         ctl                    device manager dCtl block
  1877.         pPrinterPB            current printing device class's storage
  1878.  
  1879.     Output Parameters:
  1880.         
  1881.     Description:
  1882.         Asynchronous completion.
  1883.  
  1884.     Change History:
  1885.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  1886.         11 Jun 1998,    oja:        Original version.
  1887. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1888.  
  1889. void
  1890. ControlStatusRequests( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1891. {
  1892.  
  1893.     //
  1894.     //    queue a transaction to retrieve the centronics status
  1895.     //
  1896.     OSStatus        err;
  1897.     USBPB            *usbprint = &pPrinterPB->pb;
  1898.     Boolean        dosomething = false;
  1899.     
  1900. #if DEBUG
  1901.     Str255        text;
  1902.  
  1903.     sprintf( (char *)text, " PrinterClass ControlStatus: %d", ((CntrlParam *) pb)->csCode );
  1904.     text[0] = cstrlen((char *)text); // c2pstr
  1905.     USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
  1906. #endif
  1907.  
  1908.     switch( ((CntrlParam *) pb)->csCode )
  1909.     {
  1910.     case kDrvrCentronicsStatus:
  1911.         dosomething = true;
  1912.         CentronicsStatus( usbprint,  *((Ptr *)((CntrlParam *) pb)->csParam), pPrinterPB->interfaceNumber );
  1913.         break;
  1914.     case kDrvr1284IdString:
  1915.         dosomething = true;
  1916.         CapabilityRequest( usbprint,
  1917.                                 *((Ptr *)((CntrlParam *) pb)->csParam),
  1918.                                 *((long *) &((CntrlParam *) pb)->csParam[4]),
  1919.                                 pPrinterPB->configurationNumber,        // configuration
  1920.                                 pPrinterPB->interfaceNumber,
  1921.                                 pPrinterPB->alternateSetting);
  1922.         break;
  1923.     case kDrvrSoftReset:
  1924.         dosomething = true;
  1925.         SoftReset( usbprint, pPrinterPB->interfaceNumber );
  1926.         break;
  1927.     default:
  1928.         break;
  1929.     }
  1930.  
  1931.     if ( !dosomething )
  1932.         pb->ioResult = paramErr;
  1933.     else
  1934.     {
  1935.         SetNullUSBParamBlock(pPrinterPB->deviceRef,  usbprint );
  1936.         usbprint->usbBuffer = 0;
  1937.         usbprint->usbActCount = 0;
  1938.         usbprint->usbReqCount = 0;
  1939.         usbprint->usbCompletion = (USBCompletion)CompletionProc;
  1940.         usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1941.     
  1942.         pb->ioResult = ioInProgress;
  1943.         pPrinterPB->statusDrvr.pb = pb;
  1944.         pPrinterPB->statusDrvr.ctl = ctl;
  1945.     
  1946.         err = USBDeviceRequest(usbprint);
  1947.         if(immediateError(err))
  1948.         {
  1949.             USBExpertFatalError(usbprint->usbReference, err, "\p" kStrPrinterClass "StatusControlRequests", 0);
  1950.             pb->ioResult = err;
  1951.         }
  1952.     }
  1953. }
  1954.  
  1955.  
  1956. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1957.     Name:        PrinterDeviceCompletionProc
  1958.  
  1959.     Input Parameters:    
  1960.         pb                refCon tells which state we're completing
  1961.  
  1962.     Output Parameters:
  1963.         <none>
  1964.         
  1965.     Description:
  1966.         Complete asynch transactions initiated by PrinterDeviceInitiateTransaction.
  1967.  
  1968.     Change History:
  1969.         17 Aug 1998,    oja:        don't retry high level errors (support hot unplug of root hub)
  1970.         20 Jul 1998,    oja:        clear pipe stall before retrying
  1971.         15 May 1998,    oja:        added missing break for GetCapabilityString
  1972.                                         reworked GetFullConfiguration to properly handle case
  1973.                                             where there's only one interface
  1974.         26 Mar 1998,    oja:        set info 1 to DEBUG StateStr
  1975.                                         (distinguishes completion from initiate)
  1976.         28 Feb 1998,    oja:        Original version.
  1977. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1978.  
  1979. static void 
  1980. PrinterDeviceCompletionProc(USBPB *pb)
  1981. {
  1982.     register struct usbPrinterPBStruct *pPrinterPB;
  1983.     OSStatus                                        err;
  1984.  
  1985.     
  1986.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  1987.  
  1988.     pPrinterPB->transDepth--; 
  1989.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  1990.     {
  1991.         USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "CompletionProc Illegal Transaction Depth", pPrinterPB->transDepth );
  1992.     }
  1993.  
  1994.     IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, StateStr(pPrinterPB->pb.usbRefcon, kPString) , 1 ) );
  1995.  
  1996.     pPrinterPB->delayInProgress = false;
  1997.     
  1998.     if ( pPrinterPB->terminating )
  1999.     {
  2000.         //    if we've been hot unplugged
  2001.         //        don't startup any new transactions
  2002.         //     allow PrintDriverFinalize to continue
  2003.         pPrinterPB->pb.usbStatus = kUSBAbortedError;
  2004.         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2005.     }
  2006.     
  2007.  
  2008.     switch( pPrinterPB->pb.usbStatus )
  2009.     {
  2010.         case kUSBPending:
  2011.         case noErr:
  2012.             pPrinterPB->pb.usbRefcon &= ~kRetryTransaction;
  2013.             pPrinterPB->retryCount = kPrinterRetryCount;
  2014.             break;
  2015.             
  2016.         case kUSBLinkErr:
  2017.         case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  2018.         case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  2019.         case kUSBDataToggleErr:                            /*  Pipe stall, Bad data toggle */
  2020.         case kUSBNotRespondingErr:                        /*  Pipe stall, No device, device hung */
  2021.         case kUSBPIDCheckErr:                            /*  Pipe stall, PID CRC error */
  2022.         case kUSBWrongPIDErr:                            /*  Pipe stall, Bad or wrong PID */
  2023.         
  2024.             USBClearPipeStallByReference(pPrinterPB->deviceRef);  // we got an error, try to clear any stalls
  2025.             USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass "    retry", pPrinterPB->pb.usbStatus);
  2026.             
  2027.             // clear out the transaction pending flag
  2028.             pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2029.             pPrinterPB->pb.usbRefcon |= kRetryTransaction;
  2030.             pPrinterPB->retryCount--;
  2031.             if (!pPrinterPB->retryCount)
  2032.             {
  2033.                 USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "Retry failed", pPrinterPB->pb.usbRefcon & ~kRetryTransaction);
  2034.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2035.             } 
  2036.             else 
  2037.             {
  2038.                 pPrinterPB->pb.usbStatus = noErr;             // let's retry one more time
  2039.             }
  2040.             break;
  2041.             
  2042.         case kUSBNotFound:
  2043.             break;
  2044.             
  2045.         case kUSBAbortedError:                        /* user cancel, or hot unplug */
  2046.         default:
  2047.             // clear out the transaction pending flag
  2048.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2049.             pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2050.             pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2051.             break;
  2052.     }
  2053.  
  2054.     if (pPrinterPB->pb.usbRefcon & kTransactionPending)             
  2055.     {            
  2056.         int    length;
  2057.     
  2058.         //
  2059.         //    advance to the next state
  2060.         //
  2061.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2062.         switch(pPrinterPB->pb.usbRefcon)
  2063.         {
  2064.             case kFindInterface_bidirectional:
  2065.                 USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"kFindInterface_bidirectional completed", pPrinterPB->pb.usb.cntl.WIndex);
  2066.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2067.                 {
  2068.                     if ((pPrinterPB->pb.usbClassType == kUSBPrintingClass) && 
  2069.                         (pPrinterPB->pb.usbSubclass == kUSBPrinterSubclass) &&
  2070.                         (pPrinterPB->pb.usbProtocol == kUSBPrinterBidirectionalProtocol))
  2071.                     {
  2072.                         USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"Found bidirection interface at alt setting ", pPrinterPB->pb.usbOther);
  2073.                         pPrinterPB->configurationNumber = pPrinterPB->pb.usb.cntl.WValue;
  2074.                         pPrinterPB->alternateSetting = pPrinterPB->pb.usbOther;
  2075.                         pPrinterPB->printerProtocol = kUSBPrinterBidirectionalProtocol;
  2076.                         if (pPrinterPB->pInterfaceDescriptor)
  2077.                         {
  2078.                             if (pPrinterPB->interfaceNumber == pPrinterPB->pb.usb.cntl.WIndex)
  2079.                             {
  2080.                                 pPrinterPB->pb.usbRefcon = kSetInterface;
  2081.                             }
  2082.                             else
  2083.                             {
  2084.                                 USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_Bidirectional didn't find the right interface", 0);
  2085.                             }
  2086.                         }
  2087.                         else
  2088.                         {
  2089.                             pPrinterPB->pb.usbRefcon = kOpenDevice;
  2090.                             pPrinterPB->interfaceNumber = pPrinterPB->pb.usb.cntl.WIndex;
  2091.                         }
  2092.                     }
  2093.                 }
  2094.                 else
  2095.                 {
  2096.                     if ( pPrinterPB->pb.usbStatus == kUSBNotFound )
  2097.                     {
  2098.                         USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"Bidirectional interface was not found", pPrinterPB->pb.usb.cntl.WIndex);
  2099.                         pPrinterPB->pb.usbRefcon = kFindInterface_unidirectional;
  2100.                     }
  2101.                     else
  2102.                     {
  2103.                         USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_bidirectional failed", 0);
  2104.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2105.                     }
  2106.                 }
  2107.                 break;
  2108.                 
  2109.             case kFindInterface_unidirectional:
  2110.                 USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"kFindInterface_bidirectional completed", pPrinterPB->pb.usb.cntl.WIndex);
  2111.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2112.                 {
  2113.                     if ((pPrinterPB->pb.usbClassType == kUSBPrintingClass) && 
  2114.                         (pPrinterPB->pb.usbSubclass == kUSBPrinterSubclass) &&
  2115.                         (pPrinterPB->pb.usbProtocol == kUSBPrinterBidirectionalProtocol))
  2116.                     {
  2117.                         USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"Found unidirection interface at alt setting ", pPrinterPB->pb.usbOther);
  2118.                         pPrinterPB->pb.usbRefcon = kOpenDevice;
  2119.                         pPrinterPB->configurationNumber = pPrinterPB->pb.usb.cntl.WValue;
  2120.                         pPrinterPB->alternateSetting = pPrinterPB->pb.usbOther;
  2121.                         pPrinterPB->printerProtocol = kUSBPrinterUnidirectionalProtocol;
  2122.                         if (pPrinterPB->pInterfaceDescriptor)
  2123.                         {
  2124.                             if (pPrinterPB->interfaceNumber == pPrinterPB->pb.usb.cntl.WIndex)
  2125.                             {
  2126.                                 pPrinterPB->pb.usbRefcon = kSetInterface;
  2127.                             }
  2128.                             else
  2129.                             {
  2130.                                 USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_Unidirectional didn't find the right interface", 0);
  2131.                             }
  2132.                         }
  2133.                         else
  2134.                         {
  2135.                             pPrinterPB->pb.usbRefcon = kOpenDevice;
  2136.                             pPrinterPB->interfaceNumber = pPrinterPB->pb.usb.cntl.WIndex;
  2137.                         }
  2138.                     }
  2139.                 }
  2140.                 else
  2141.                 {
  2142.                     if ( pPrinterPB->pb.usbStatus == kUSBNotFound )
  2143.                     {
  2144.                         USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"Unidirectional interface was not found", pPrinterPB->pb.usb.cntl.WIndex);
  2145.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2146.                     }
  2147.                     else
  2148.                     {
  2149.                         USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_unidirectional failed", 0);
  2150.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2151.                     }
  2152.                 }
  2153.                 break;
  2154.                 
  2155.             case kOpenDevice:
  2156.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2157.                 {
  2158.                     USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"kOpenDevice completed", pPrinterPB->pb.usbStatus);
  2159.                     pPrinterPB->pb.usbRefcon = kNewInterfaceRef;
  2160.                 }
  2161.                 else
  2162.                 {
  2163.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kOpenDevice failed", 0);
  2164.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2165.                 }
  2166.                 break;
  2167.                 
  2168.             case kNewInterfaceRef:
  2169.                 USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"kNewInterfaceRef completed", pPrinterPB->pb.usbReference);
  2170.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2171.                 {
  2172.                     pPrinterPB->interfaceRef = pPrinterPB->pb.usbReference;
  2173.                     pPrinterPB->pb.usbRefcon = kSetInterface;
  2174.                 }
  2175.                 else
  2176.                 {
  2177.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kNewInterfaceRef failed", 0);
  2178.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2179.                 }
  2180.                 break;
  2181.             
  2182.             case kSetInterface:
  2183.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kSetInterface completed", 0);
  2184.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2185.                 {
  2186.                     pPrinterPB->pb.usbRefcon = kConfigureInterface;
  2187.                 }
  2188.                 else
  2189.                 {
  2190.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kSetInterface failed", 0);
  2191.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2192.                 }
  2193.                 break;
  2194.             
  2195.             case kConfigureInterface:
  2196.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kConfigureInterface completed, pipes = ", pPrinterPB->pb.usbOther);
  2197.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2198.                 {
  2199.                     pPrinterPB->pipeCount = pPrinterPB->pb.usbOther;
  2200.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2201.                 }
  2202.                 else
  2203.                 {
  2204.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kConfigureInterface failed", 0);
  2205.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2206.                 }
  2207.                 break;
  2208.             
  2209.             case kGetCapabilityString:
  2210.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetCapabilityString completed", pPrinterPB->pb.usbStatus);
  2211.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2212.                 {
  2213.                     //
  2214.                     //    In the short term (fall '98) several vendors are planning on shipping 
  2215.                     //        devices with a parallel port and using the Lucent USS-720 USB-to-parallel hardware.
  2216.                     //    Unfortunately this isn't an ideal solution from the USB perspective:
  2217.                     //        users can leave the printer off while the cable responds that there's
  2218.                     //        a printer connected. Then we have no way of using the DEVICE_ID
  2219.                     //        string to tag the printer and register it.
  2220.                     //    To alleviate this situation, we repeatedly poll the USS-720 if the DEVICE_ID
  2221.                     //        string is null. Every few seconds we'll retry this state.
  2222.                     //    At some point the user wants to print and switches on the printer. The class
  2223.                     //    driver then picks up from here and registers the device properly.
  2224.                     //
  2225.                     length = pPrinterPB->pCapabilityString[1] | (pPrinterPB->pCapabilityString[0] << 8);
  2226.                     if ( IsLucentCable( &pPrinterPB->deviceDescriptor ) && pPrinterPB->pb.usbActCount == 0 )
  2227.                         pPrinterPB->pb.usbRefcon = kDelayGetCapability;
  2228.                     else
  2229.                         pPrinterPB->pb.usbRefcon = kFindBulkOutPipe;
  2230.                 }
  2231.                 else
  2232.                 {
  2233.                     if ( pPrinterPB->pb.usbStatus == kUSBOverRunErr )
  2234.                     {
  2235.                         //
  2236.                         //    if we've haven't managed to read the whole capability string
  2237.                         //        we need to allocate memory and read it in by initiating kGetFullCapabilityString
  2238.                         //
  2239.                         length = pPrinterPB->pCapabilityString[1] | (pPrinterPB->pCapabilityString[0] << 8);
  2240.     
  2241.                         if ( length > sizeof(pPrinterPB->capability) &&
  2242.                                 pPrinterPB->pb.usbRefcon == kGetCapabilityString )
  2243.                             pPrinterPB->pb.usbRefcon = kAllocateCapabilityMem;
  2244.                     }
  2245.                     else
  2246.                     {
  2247.                         USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetCapabilityString failed", 0);
  2248.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2249.                     }
  2250.                 }
  2251.                 break;
  2252.                 
  2253.             case kDelayGetCapability:
  2254.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kDelayGetCapability completed", pPrinterPB->pb.usbStatus);
  2255.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2256.                 {
  2257.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2258.                 }
  2259.                 else
  2260.                 {
  2261.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kDelayGetCapability failed", 0);
  2262.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2263.                 }
  2264.                 break;
  2265.                 
  2266.             case kAllocateCapabilityMem:
  2267.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kAllocateCapabilityMem completed", pPrinterPB->pb.usbStatus);
  2268.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2269.                 {
  2270.                     pPrinterPB->pCapabilityString = pPrinterPB->pb.usbBuffer;
  2271.                     pPrinterPB->pb.usbRefcon = kGetFullCapabilityString;    
  2272.                 }
  2273.                 else
  2274.                 {
  2275.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kAllocateCapabilityMem failed", 0);
  2276.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2277.                 }
  2278.                 break;
  2279.             
  2280.             case kGetFullCapabilityString:
  2281.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetFullCapabilityString completed", pPrinterPB->pb.usbStatus);
  2282.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2283.                 {
  2284.                     pPrinterPB->pb.usbRefcon = kGetInterface;
  2285.                 }
  2286.                 else
  2287.                 {
  2288.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetFullCapabilityString failed", 0);
  2289.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2290.                 }
  2291.                 break;
  2292.                 
  2293.             case kGetInterface:
  2294.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetInterface completed", pPrinterPB->pb.usbStatus);
  2295.                 if (( pPrinterPB->pb.usbStatus == noErr ) && (pPrinterPB->whichAltInterface == pPrinterPB->alternateSetting))
  2296.                 {
  2297.                     pPrinterPB->pb.usbRefcon = kFindBulkOutPipe;
  2298.                 }
  2299.                 else
  2300.                 {
  2301.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetInterface - wrong interface selected", pPrinterPB->whichAltInterface);
  2302.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2303.                 }
  2304.                 break;
  2305.  
  2306.             case kFindBulkOutPipe:
  2307.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkOutPipe completed", pPrinterPB->pb.usbReference);
  2308.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2309.                 {
  2310.                     pPrinterPB->writePipeRef = pPrinterPB->pb.usbReference;             // remember the ref
  2311.                     pPrinterPB->out = pPrinterPB->pb;                                        // copy the paramblock
  2312.                     pPrinterPB->out.usbCompletion =  (USBCompletion) NULL;            // for finalize
  2313.  
  2314.                     if ( pPrinterPB->printerProtocol == kUSBPrinterBidirectionalProtocol )
  2315.                         pPrinterPB->pb.usbRefcon = kFindBulkInPipe;
  2316.                     else
  2317.                         pPrinterPB->pb.usbRefcon = kTaskTimeRequired;
  2318.                 }
  2319.                 else
  2320.                 {
  2321.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindBulkOutPipe failed", 0);
  2322.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2323.                 }
  2324.                 break;
  2325.                 
  2326.             case kFindBulkInPipe:
  2327.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kFindBulkInPipe completed", pPrinterPB->pb.usbReference);
  2328.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2329.                 {
  2330.                     pPrinterPB->readPipeRef = pPrinterPB->pb.usbReference;
  2331.                     pPrinterPB->in = pPrinterPB->pb;                                            // copy the paramblock
  2332.                     pPrinterPB->in.usbCompletion =  (USBCompletion) NULL;                // for finalize
  2333.  
  2334.                     pPrinterPB->pb.usbRefcon = kTaskTimeRequired;
  2335.                 }
  2336.                 else
  2337.                 {
  2338.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindBulkInPipe failed", 0);
  2339.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2340.                 }
  2341.                 break;
  2342.                 
  2343.             case kTaskTimeRequired:
  2344.                 USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired completed (now at task time)", pPrinterPB->pb.usbReference);
  2345.             //
  2346.             //    once we know what device we're dealing with
  2347.             //        open the i/o channel(s) to the device
  2348.             //        and enter it in the name registry
  2349.             //
  2350.                 err = InstallDrivers( pPrinterPB );
  2351.                 if ( err == noErr )
  2352.                 {
  2353.                     USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired - drivers installed", pPrinterPB->pb.usbReference);
  2354.                     err = RegisterDevice( pPrinterPB );
  2355.                     if ( err == noErr )
  2356.                     {
  2357.                         USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired - RegisterDevice successful", pPrinterPB->pb.usbReference);
  2358.                     }
  2359.                     else
  2360.                     {
  2361.                         USBExpertFatalError(pPrinterPB->interfaceRef, err, "\p" kStrPrinterClass "kTaskTimeRequired - RegisterDevice failed", 0);
  2362.                     }
  2363.                 }
  2364.                 else
  2365.                 {
  2366.                     USBExpertFatalError(pPrinterPB->interfaceRef, err, "\p" kStrPrinterClass "kTaskTimeRequired - InstallDrivers failed", 0);
  2367.                 }
  2368.     
  2369.                 pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;                    // Finalize
  2370.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2371.                 {
  2372.                     pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  2373.                     pPrinterPB->printerConfigured = true;
  2374.                 }
  2375.                 else
  2376.                 {
  2377.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "RegisterDevice failed", 0);
  2378.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2379.                 }
  2380.                 break;
  2381.                 
  2382.             case kGetCentronicsStatus:
  2383.                 //
  2384.                 //    if InitiateTransaction fell through on it's kTaskTimeRequired case we'll end up here
  2385.                 //
  2386.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2387.                 {
  2388. #if DEBUG
  2389.                     Str255    text, te;
  2390.                     hexstr( sizeof(char), &pPrinterPB->centronics.b, (char *) te );
  2391.                     sprintf( (char *)text, " PrinterClass Status: %s", te );
  2392.                     text[0] = cstrlen((char *)text); // c2pstr
  2393.                     USBExpertStatus(pPrinterPB->interfaceRef, text, pb->usbStatus );
  2394. #endif
  2395. #if DEBUG
  2396.                     if ( !pPrinterPB->centronics.status.notError )
  2397.                     {
  2398.                         USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass "Error at printer", pPrinterPB->pb.usbStatus);
  2399.                     }
  2400.                     if ( pPrinterPB->centronics.status.paperError )
  2401.                     {
  2402.                         USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass "Check paper", pPrinterPB->pb.usbStatus);
  2403.                     }
  2404.                     if ( !pPrinterPB->centronics.status.select )
  2405.                     {
  2406.                         USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass "printer offline", pPrinterPB->pb.usbStatus);
  2407.                     }
  2408. #endif
  2409.                     pPrinterPB->pb.usbRefcon = kDelayGetCentronicsStatus;
  2410.                 }
  2411.                 break;
  2412.                 
  2413.             case kDelayGetCentronicsStatus:
  2414.                 //
  2415.                 //    loop around continually getting status
  2416.                 //
  2417.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2418.                 {
  2419.                     pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  2420.                 }
  2421.                 break;
  2422.             case kNilCompletion:
  2423.             default:
  2424.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2425.                     pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  2426.                 break;
  2427.         }
  2428.     }
  2429.     
  2430.     // did the removal notification get called?  If so, don't start another transaction.  Just exit
  2431.    if (!pPrinterPB->terminating)
  2432.     {
  2433.         if (pPrinterPB->pb.usbStatus == noErr )
  2434.         {
  2435.             if (!(pPrinterPB->pb.usbRefcon & kReturnFromDriver))
  2436.                 PrinterDeviceInitiateTransaction(pb);
  2437.         }
  2438.         else if ( pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  2439.         {
  2440.             USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, StateStr(pPrinterPB->pb.usbRefcon, kPString), pPrinterPB->pb.usbRefcon);
  2441.             USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, USBStatusStr(pPrinterPB->pb.usbStatus, kPString), 0);
  2442.         }
  2443.     }
  2444.     else
  2445.     {
  2446.         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2447.     }
  2448.     
  2449.     // If we're exiting the driver, then make certain the completion routine is set to NULL
  2450.     // this lets the driver removal task know that there's nothing pending.
  2451.     if ( pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  2452.     {
  2453.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  2454.     }
  2455. }
  2456.  
  2457. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2458.     Name:        PrinterDeviceInitiateTransaction
  2459.  
  2460.     Input Parameters:    
  2461.         pb            USB parameter block
  2462.         
  2463.     Output Parameters:
  2464.         
  2465.     Description:
  2466.         Since USB transactions are asynchronous we use the refCon field
  2467.         in the parameter block to implement the following logic via a state machine.
  2468.  
  2469.         Start out by getting the device configuration descriptor
  2470.         If the device has more than one printing interface
  2471.             If a bidirectional interface exists
  2472.                 select it
  2473.             Else
  2474.                 select the (mandatory) unidirectional interface
  2475.         Get the (manadatory) 1284 capability string
  2476.         Open pipes to the BulkOut (and optional BulkIn) endpoints
  2477.         Install read and write drivers in the unit table
  2478.         Using information from the capability string
  2479.             enter the printer in the MacOS name registry.
  2480.         
  2481.  
  2482.     Change History:
  2483.         15 May 1998,    oja:        cleanup error/status messages
  2484.                                         handle setinterface correctly if only one
  2485.                                             interface is available
  2486.         28 Feb 1998,    oja:        Original version.
  2487. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2488. void
  2489. PrinterDeviceInitiateTransaction(USBPB *pb)
  2490. {
  2491.     register struct usbPrinterPBStruct    *pPrinterPB;
  2492.     int                                            length;
  2493.     OSStatus                                        err;
  2494.  
  2495.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  2496.     
  2497.     pPrinterPB->transDepth++;
  2498.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  2499.     {
  2500.         USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction illegal transaction depth", 0);
  2501.     }
  2502.     IF_DEBUG( USBExpertStatus( pPrinterPB->deviceRef, StateStr(pPrinterPB->pb.usbRefcon, kPString), 0) );     
  2503.  
  2504.     pPrinterPB->delayInProgress = false;
  2505.     switch(pPrinterPB->pb.usbRefcon & ~kRetryTransaction)
  2506.     {
  2507.         case kFindInterface_bidirectional:
  2508.             USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass"kFindInterface_bidirectional", 0);
  2509.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  2510.             
  2511.             pPrinterPB->pb.usbBuffer = 0;
  2512.             pPrinterPB->pb.usbActCount = 0;
  2513.             pPrinterPB->pb.usbReqCount = 0;
  2514.             pPrinterPB->pb.usb.cntl.WIndex = 0;
  2515.             pPrinterPB->pb.usb.cntl.WValue = 0;
  2516.             pPrinterPB->pb.usbClassType = kUSBPrintingClass;
  2517.             pPrinterPB->pb.usbSubclass = kUSBPrinterSubclass;
  2518.             pPrinterPB->pb.usbProtocol = kUSBPrinterBidirectionalProtocol;
  2519.             
  2520.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2521.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2522.             err = USBFindNextInterface(pb);
  2523.             if(immediateError(err))
  2524.             {
  2525.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kFindInterface_bidirectional - immediate error", err);
  2526.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2527.             }
  2528.             break;
  2529.     
  2530.         case kFindInterface_unidirectional:
  2531.             USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass"kFindInterface_unidirectional", 0);
  2532.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  2533.             
  2534.             pPrinterPB->pb.usbBuffer = 0;
  2535.             pPrinterPB->pb.usbActCount = 0;
  2536.             pPrinterPB->pb.usbReqCount = 0;
  2537.             pPrinterPB->pb.usb.cntl.WIndex = 0;
  2538.             pPrinterPB->pb.usb.cntl.WValue = 0;
  2539.             pPrinterPB->pb.usbClassType = kUSBPrintingClass;
  2540.             pPrinterPB->pb.usbSubclass = kUSBPrinterSubclass;
  2541.             pPrinterPB->pb.usbProtocol = kUSBPrinterUnidirectionalProtocol;
  2542.             
  2543.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2544.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2545.             err = USBFindNextInterface(pb);
  2546.             if(immediateError(err))
  2547.             {
  2548.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kFindInterface_unidirectional - immediate error", err);
  2549.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2550.             }
  2551.             break;
  2552.     
  2553.         case kOpenDevice:
  2554.             USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass"kOpenDevice", 0);
  2555.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  2556.             
  2557.             pPrinterPB->pb.usbBuffer = 0;
  2558.             pPrinterPB->pb.usbActCount = 0;
  2559.             pPrinterPB->pb.usbReqCount = 0;
  2560.             pPrinterPB->pb.usb.cntl.WValue = pPrinterPB->configurationNumber;
  2561.             
  2562.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2563.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2564.             err = USBOpenDevice(pb);
  2565.             if(immediateError(err))
  2566.             {
  2567.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBOpenDevice - immediate error", err);
  2568.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2569.             }
  2570.             break;
  2571.             
  2572.         case kNewInterfaceRef:
  2573.             USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass"kNewInterfaceRef for interface number", pPrinterPB->interfaceNumber);
  2574.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  2575.             
  2576.             pPrinterPB->pb.usbBuffer = 0;
  2577.             pPrinterPB->pb.usbActCount = 0;
  2578.             pPrinterPB->pb.usbReqCount = 0;
  2579.             pPrinterPB->pb.usb.cntl.WIndex = pPrinterPB->interfaceNumber;
  2580.             
  2581.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2582.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2583.             err = USBNewInterfaceRef(pb);
  2584.             if(immediateError(err))
  2585.             {
  2586.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBNewInterfaceRef - immediate error", err);
  2587.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2588.             }
  2589.             break;
  2590.             
  2591.  
  2592.         case kSetInterface:
  2593.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kSetInterface to alternate setting", pPrinterPB->alternateSetting);
  2594.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2595.             
  2596.             pPrinterPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBInterface);
  2597.         
  2598.             pPrinterPB->pb.usb.cntl.BRequest = kUSBRqSetInterface;
  2599.             pPrinterPB->pb.usb.cntl.WValue = pPrinterPB->alternateSetting;        // alternate setting
  2600.             pPrinterPB->pb.usb.cntl.WIndex = pPrinterPB->interfaceNumber;        // interface
  2601.         
  2602.             pPrinterPB->pb.usbReqCount = 0;
  2603.             pPrinterPB->pb.usbBuffer = NULL;
  2604.         
  2605.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2606.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2607.             err = USBDeviceRequest(pb);
  2608.             if(immediateError(err))
  2609.             {
  2610.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kSetInterface - immediate error", err);
  2611.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2612.             }
  2613.             break;
  2614.  
  2615.  
  2616.         case kConfigureInterface:
  2617.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kConfigureInterface for alternate setting", pPrinterPB->alternateSetting);
  2618.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2619.             
  2620.             pPrinterPB->pb.usbBuffer = 0;
  2621.             pPrinterPB->pb.usbActCount = 0;
  2622.             pPrinterPB->pb.usbReqCount = 0;
  2623.             pPrinterPB->pb.usbOther = pPrinterPB->alternateSetting;
  2624.             
  2625.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2626.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2627.             err = USBConfigureInterface(pb);
  2628.             if(immediateError(err))
  2629.             {
  2630.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBConfigureInterface - immediate error)", err);
  2631.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2632.             }
  2633.             break;
  2634.             
  2635.         case kGetCapabilityString:
  2636.             //
  2637.             //    once the interface (and alternate) is assinged
  2638.             //        we can retreive the 1284 capability string to see what kind of printer
  2639.             //        is attached
  2640.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kGetCapabilityString", 0);
  2641.             pPrinterPB->pCapabilityString = pPrinterPB->capability;
  2642.             GetCapability( pPrinterPB, pPrinterPB->pCapabilityString, sizeof(pPrinterPB->capability) );
  2643.             break;
  2644.             
  2645.         case kDelayGetCapability:
  2646.             //
  2647.             //    USS-720 USB-parallel cable: couldn't get the capability string because the printer is off
  2648.             //        Delay a few seconds and try again.
  2649.             //        Will succeed when the user turns the printer on.
  2650.             //
  2651.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kDelayGetCapability", 0);
  2652.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2653.             
  2654.             pPrinterPB->pb.usbBuffer = 0;
  2655.             pPrinterPB->pb.usbActCount = 0;
  2656.             pPrinterPB->pb.usbReqCount = kUSS720MillisecondDelay;
  2657.             pPrinterPB->pb.usbFlags = kUSBTaskTimeFlag;
  2658.             
  2659.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2660.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2661.             pPrinterPB->delayInProgress = true;
  2662.             err = USBDelay(&pPrinterPB->pb);
  2663.             if(immediateError(err))
  2664.             {
  2665.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCapability - immediate error", 0);
  2666.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2667.             }
  2668.             break;
  2669.             
  2670.         case kAllocateCapabilityMem:
  2671.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kAllocateCapabilityMem", 0);
  2672.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2673.             
  2674.             length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
  2675.             pPrinterPB->pb.usbBuffer = 0;
  2676.             pPrinterPB->pb.usbActCount = 0;
  2677.             pPrinterPB->pb.usbReqCount = length;
  2678.             pPrinterPB->pb.usbFlags = 0;
  2679.             
  2680.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2681.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2682.             err = USBAllocMem(&pPrinterPB->pb);
  2683.             if(immediateError(err))
  2684.             {
  2685.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kAllocateCapabilityMem - immediate error", 0);
  2686.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2687.             }
  2688.             break;
  2689.         
  2690.         case kGetFullCapabilityString:
  2691.             //
  2692.             // the capability string was too long to fit in the statically allocated space
  2693.             // need to release this memory when we finalize our driver
  2694.             //
  2695.  
  2696.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kGetFullCapabilityString", 0);
  2697.             length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
  2698.             if ( pPrinterPB->pCapabilityString )
  2699.                 GetCapability( pPrinterPB, pPrinterPB->pCapabilityString, length );
  2700.             else
  2701.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, "\p" kStrPrinterClass "Can't allocate capability memory", 0);
  2702.             break;
  2703.             
  2704.         case kGetInterface:
  2705.             // failsafe check that we've got the right setup
  2706.             //    it's possible the device didn't respond to our SetInterface
  2707.             GetInterface( &pPrinterPB->pb, &pPrinterPB->whichAltInterface );
  2708.             break;
  2709.  
  2710.         case kFindBulkOutPipe:
  2711.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkOutPipe", 0);
  2712.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2713.             
  2714.             pPrinterPB->pb.usbBuffer = 0;
  2715.             pPrinterPB->pb.usbActCount = 0;
  2716.             pPrinterPB->pb.usbReqCount = 0;
  2717.             pPrinterPB->pb.usbFlags = kUSBOut;
  2718.             pPrinterPB->pb.usbClassType = kUSBBulk;
  2719.             
  2720.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2721.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2722.             err = USBFindNextPipe( &pPrinterPB->pb );
  2723.             if (immediateError(err))
  2724.             {
  2725.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, kStrPrinterClass"kFindBulkOutPipe - immediate error", err);
  2726.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2727.             }
  2728.             break;
  2729.             
  2730.         case kFindBulkInPipe:    
  2731.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkInPipe", 0);
  2732.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2733.             
  2734.             pPrinterPB->pb.usbBuffer = 0;
  2735.             pPrinterPB->pb.usbActCount = 0;
  2736.             pPrinterPB->pb.usbReqCount = 0;
  2737.             pPrinterPB->pb.usbFlags = kUSBIn;
  2738.             pPrinterPB->pb.usbClassType = kUSBBulk;
  2739.             
  2740.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2741.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2742.             err = USBFindNextPipe( &pPrinterPB->pb );
  2743.             if (immediateError(err))
  2744.             {
  2745.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, "\p"kStrPrinterClass"kFindBulkInPipe - immediate error", err);
  2746.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2747.             }
  2748.             break;
  2749.             
  2750.         case kTaskTimeRequired:
  2751.             USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kTaskTimeRequired", 0);
  2752.              // to stress test usb bus, fallthrough to kGetCentronicsStatus 
  2753.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2754.             
  2755.             pPrinterPB->pb.usbBuffer = 0;
  2756.             pPrinterPB->pb.usbActCount = 0;
  2757.             pPrinterPB->pb.usbReqCount = kUSBNoDelay;
  2758.             pPrinterPB->pb.usbFlags = kUSBTaskTimeFlag;
  2759.             
  2760.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2761.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2762.             pPrinterPB->delayInProgress = true;
  2763.             err = USBDelay(&pPrinterPB->pb);
  2764.             if(immediateError(err))
  2765.             {
  2766.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kTaskTimeRequired - immediate error", 0);
  2767.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2768.             }
  2769.             break;
  2770.  
  2771.         case kGetCentronicsStatus:
  2772.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2773.  
  2774.             CentronicsStatus( &pPrinterPB->pb,  &pPrinterPB->centronics.b, pPrinterPB->interfaceNumber );
  2775.             
  2776.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2777.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2778.             err = USBDeviceRequest(&pPrinterPB->pb);
  2779.             if(immediateError(err))
  2780.             {
  2781.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kGetCentronicsStatus Immediate error", 0);
  2782.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2783.             }
  2784.             break;
  2785.             
  2786.         case kDelayGetCentronicsStatus:
  2787.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2788.  
  2789.             pPrinterPB->pb.usbBuffer = 0;
  2790.             pPrinterPB->pb.usbActCount = 0;
  2791.             pPrinterPB->pb.usbReqCount = kUSS720StatusMSDelay;
  2792.             
  2793.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2794.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2795.             pPrinterPB->delayInProgress = true;
  2796.             err = USBDelay(&pPrinterPB->pb);
  2797.             if(immediateError(err))
  2798.             {
  2799.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCentronicsStatus - immediate error", 0);
  2800.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2801.             }
  2802.             break;
  2803.             
  2804.         default:
  2805.             USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction - unknown state", pPrinterPB->pb.usbRefcon);
  2806.             pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2807.             break;
  2808.     }
  2809.     
  2810.     if (pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  2811.     {
  2812.         pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2813.     }
  2814. }
  2815.  
  2816.  
  2817. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2818.     Name:        PrintDriverEntry
  2819.  
  2820.     Input Parameters:    
  2821.         
  2822.     Output Parameters:
  2823.         
  2824.     Description:
  2825.         This is where the system instantiates a USB printing device.
  2826.  
  2827.         We need to install drivers in the MacOS unitTable, and a reference
  2828.         in the name registry.
  2829.         
  2830.         But the information we need to do this is only available after some 
  2831.         USB transactions have completed. So we initiate here a series of asynchronous
  2832.         USB operations to get that information (by calling the first 
  2833.  
  2834.     Change History:
  2835.         31 Jul 1998,    oja:        page-aligned double buffer i/o
  2836.         30 Jun 1998,    oja:        change CentronicsStatus to ControlStatusRequests
  2837.         28 Feb 1998,    oja:        Original version.
  2838. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2839. void 
  2840. PrintDriverEntry(
  2841.     USBDeviceRef                    deviceRef,
  2842.     USBDeviceDescriptorPtr        pDeviceDesc,
  2843.     USBInterfaceDescriptorPtr    pInterfaceDesc,
  2844.     UInt32                            interfaceNumber
  2845.     )
  2846. {
  2847.     static Boolean        beenThereDoneThat = false;
  2848.     OSStatus                err;
  2849.     
  2850.     
  2851.     RoutineDescriptor qw = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBWriteProcInfo, QueueWrite);
  2852.     RoutineDescriptor qr = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBReadProcInfo, QueueRead);
  2853.     RoutineDescriptor qa = BUILD_ROUTINE_DESCRIPTOR( uppAbortProcInfo, Abort);
  2854.     RoutineDescriptor qs = BUILD_ROUTINE_DESCRIPTOR( uppControlStatusProcInfo, ControlStatusRequests );
  2855.     
  2856.     if( !beenThereDoneThat)
  2857.     {
  2858.         beenThereDoneThat = true;
  2859.         
  2860.         //DebugStr("\pIn Printer Driver Entry");
  2861.         USBExpertStatus(deviceRef, "\p"kStrPrinterClass"Starting USB Printer Driver", 0);
  2862.         
  2863.         printerClassRecord.deviceDescriptor = *pDeviceDesc;    /* keep a copy of the device descriptor */
  2864.         printerClassRecord.pInterfaceDescriptor = pInterfaceDesc;
  2865.         printerClassRecord.interfaceNumber = interfaceNumber;
  2866.         
  2867.         printerClassRecord.deviceRef = deviceRef;
  2868.         printerClassRecord.interfaceRef = deviceRef;
  2869.         
  2870.         printerClassRecord.transDepth = 0;            /* init Delay Callback Depth */
  2871.     
  2872.         printerClassRecord.inRefNum =  -1;            /* initially no DRVRs added to UnitTable */
  2873.         printerClassRecord.outRefNum =  -1;    
  2874.         err = LoadResources( &printerClassRecord );
  2875.         if ( err != noErr )  
  2876.             USBExpertFatalError( deviceRef, err, "\p" kStrPrinterClass "LoadResources failed", 0);
  2877.         //
  2878.         //    routines to write and read to the device must be called by 68K DRVR
  2879.         //        so we use mixed-mode manager to dispatch between PPC and 68K
  2880.         //
  2881.         printerClassRecord.qwrite = (QueueUSBWriteUPP) &printerClassRecord.qwriteRD;
  2882.         printerClassRecord.qwriteRD = qw;
  2883.     
  2884.         printerClassRecord.qread = (QueueUSBReadUPP) &printerClassRecord.qreadRD;
  2885.         printerClassRecord.qreadRD = qr;    
  2886.         
  2887.         printerClassRecord.qstatus = (ControlStatusUPP) &printerClassRecord.qstatusRD;
  2888.         printerClassRecord.qstatusRD = qs;
  2889.  
  2890.         printerClassRecord.qabort = (AbortUPP) &printerClassRecord.qabortRD;
  2891.         printerClassRecord.qabortRD = qa;
  2892.  
  2893.         printerClassRecord.r = (QueueUSBReadUPP) QueueRead;
  2894.         printerClassRecord.w = (QueueUSBWriteUPP) QueueWrite;
  2895.         printerClassRecord.s = (ControlStatusUPP) ControlStatusRequests;
  2896.         printerClassRecord.a = (AbortUPP) Abort;
  2897.    
  2898.         SetNullUSBParamBlock( deviceRef, &printerClassRecord.pb );
  2899.         SetNullUSBParamBlock( 0, &printerClassRecord.in );        // fill in pipe ref later
  2900.         SetNullUSBParamBlock( 0, &printerClassRecord.out );    // fill in pipe ref later
  2901.  
  2902. #if DOUBLE_BUFFER
  2903.         //
  2904.         // Assume 1. TRANSFER_SIZE is a power of 2
  2905.         //    Assume 2. malignedBuffer is allocated to be 3*TRANSFER_SIZE
  2906.         //
  2907.         printerClassRecord.pageWriteAlignedBufferSize = TRANSFER_SIZE;                            // should get this from VM
  2908.         printerClassRecord.pageWriteAlignedBuffer = printerClassRecord.malignedBuffer;
  2909.         // align it below the buffer, then bring it into the range of the buffer
  2910.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) &= ~(printerClassRecord.pageWriteAlignedBufferSize - 1);    //assumption1
  2911.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) += printerClassRecord.pageWriteAlignedBufferSize;            //assumption2
  2912.  
  2913.         printerClassRecord.pageReadAlignedBufferSize = TRANSFER_SIZE;
  2914.         printerClassRecord.pageReadAlignedBuffer = printerClassRecord.pageWriteAlignedBuffer + TRANSFER_SIZE;
  2915. #endif
  2916.         printerClassRecord.terminating = false;
  2917.         printerClassRecord.printerConfigured = false;
  2918.     
  2919.         //
  2920.         //    Just to be thorough, lets hold our paramter blocks so that we won't page them at
  2921.         //        interrupt time. (We should be in the System heap and automatically held.)
  2922.         //
  2923.         HoldMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  2924.  
  2925.  
  2926.         //
  2927.         // Start out at first state
  2928.         //
  2929.         printerClassRecord.pCapabilityString = printerClassRecord.capability;
  2930.         printerClassRecord.pb.usbRefcon = kFindInterface_bidirectional;
  2931.         PrinterDeviceInitiateTransaction(&printerClassRecord.pb);
  2932.     }
  2933. }
  2934.  
  2935. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2936.     Name:        PrinterRemovalNotification
  2937.  
  2938.     Input Parameters:    
  2939.         
  2940.     Output Parameters:
  2941.         
  2942.     Description:
  2943.         release any allocated storage
  2944.         remove DRVRs from the UnitTable
  2945.  
  2946.         One small complication happens when the USS-720 cable is used. It's possible
  2947.         that the user has the device plugged in, but the printer wasn't powered on.
  2948.         In this case, our state machine is still cycling between the states 
  2949.         kDelayGetCapability and kGetCapabilityString. If we terminate before the delay
  2950.         returns we'll crash the system. We monitor terminating to handle this
  2951.         
  2952.     Change History:
  2953.         17 Aug 1998,    oja:        don't deregister if the root hub was hot unplugged
  2954.         10 Aug 1998,    oja:        call Abort to cleanup pending read/write transactions
  2955.         31 Jul 1998,    oja:        cleanup some hotplugging problems
  2956.         12 Jul 1998,    oja:        allow for hot unplugging during initial startup
  2957.                                             wait for completion if refCon indicates some
  2958.                                             transaction is in progress
  2959.         24 Apr 1998,    oja:        added call to DeregisterDevice
  2960.         28 Feb 1998,    oja:        Original version.
  2961. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2962. OSStatus
  2963. PrinterRemovalNotification( void )
  2964. {
  2965. static    Boolean    logfileclosed = false;
  2966. static    Boolean    aborted = false;
  2967. static    Boolean    deregistered = false;
  2968. static    Boolean    readpipeaborted = false;
  2969. static    Boolean    writepipeaborted = false;
  2970. static    Boolean    timedout = false;
  2971. OSStatus            result = noErr;
  2972. static unsigned long    tc = 0;
  2973.     //
  2974.     //    notify state machine not to continue
  2975.     //
  2976.     printerClassRecord.terminating = true;
  2977.     
  2978.     USBExpertStatus( printerClassRecord.deviceRef, "\p"kStrPrinterClass"Driver removal notification received", 0);
  2979.     if (!logfileclosed)
  2980.     {
  2981.         LOGGING( fclose( logfile ) );
  2982.         logfileclosed = true;
  2983.         return (OSStatus) kUSBDeviceBusy;
  2984.     }
  2985.     
  2986.     // per the Mac OS USB DDK API Ref 
  2987.     // "If the device associated with this call [USBDelay] is unplugged and its driver removed while
  2988.     //  this function call is pending, the function will not complete."
  2989.     // therefore don't hang around if a delay is in progress
  2990.     if (( printerClassRecord.pb.usbCompletion != (USBCompletion) NULL ) && (!printerClassRecord.delayInProgress))
  2991.     {
  2992.         USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Waiting for configuration to complete", printerClassRecord.pb.usbRefcon);
  2993.         return (OSStatus) kUSBDeviceBusy;
  2994.     }
  2995.     
  2996.     // Abort any outstanding write requests
  2997.     if (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL ) && (!writepipeaborted))
  2998.     {
  2999.         USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Abort write pipe", printerClassRecord.writePipeRef);
  3000.         USBAbortPipeByReference( printerClassRecord.writePipeRef );
  3001.         writepipeaborted = true;
  3002.         return (OSStatus) kUSBDeviceBusy;
  3003.     }
  3004.     
  3005.     // Abort any outstanding read requests
  3006.     if (( printerClassRecord.in.usbCompletion != (USBCompletion) NULL ) && (!readpipeaborted))
  3007.     {
  3008.         USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Abort read pipe", printerClassRecord.readPipeRef );
  3009.         USBAbortPipeByReference( printerClassRecord.readPipeRef );
  3010.         readpipeaborted = true;
  3011.         return (OSStatus) kUSBDeviceBusy;
  3012.     }
  3013.     
  3014.     // Abort any outstanding transactions
  3015.     if (!aborted)
  3016.     {
  3017.         USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Call Abort()", 0);
  3018.         Abort( 0, &printerClassRecord );
  3019.         aborted = true;
  3020.         return (OSStatus) kUSBDeviceBusy;
  3021.     }
  3022.  
  3023.     // wait up to ten seconds for the read & write routines to complete.  When they do, the completion procptrs will be NULL'd
  3024.     if (tc == 0)
  3025.         tc = TickCount() + 10*60;
  3026.         
  3027.     if ( TickCount() >= tc )
  3028.         timedout = true;
  3029.         
  3030.     if (( TickCount() < tc ) &&
  3031.          (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL) ||
  3032.           ( printerClassRecord.in.usbCompletion != (USBCompletion) NULL )))
  3033.     {
  3034.         return (OSStatus) kUSBDeviceBusy;
  3035.     }
  3036.     
  3037.     // Put the appropriate timeout message in the log
  3038.     if ( timedout )
  3039.     {
  3040.         USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"took longer than 10 seconds for read/write pipes to complete", 0);
  3041.     }
  3042.     else
  3043.     {
  3044.         USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Pipes closed normally", 0);
  3045.     }
  3046.     
  3047.     if (!deregistered)        
  3048.     {
  3049.         //
  3050.         //    remove printer from the name registry
  3051.         //
  3052.         USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Removed printer entry from nameregistry", 0);
  3053.         DeregisterDevice( &printerClassRecord );
  3054.         deregistered = true;
  3055.         return (OSStatus) kUSBDeviceBusy;
  3056.     }
  3057.  
  3058.     //
  3059.     //    release any allocated storage
  3060.     //
  3061.     if ( printerClassRecord.pCapabilityString != printerClassRecord.capability )
  3062.     {
  3063.         USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Deallocated capability string memory", 0);
  3064.         printerClassRecord.pb.usbReference = printerClassRecord.deviceRef;             
  3065.         printerClassRecord.pb.usbFlags = 0;             
  3066.         printerClassRecord.pb.usbRefcon = kDeallocateCapbilityString;             
  3067.         printerClassRecord.pb.usbBuffer = printerClassRecord.pCapabilityString;        
  3068.         printerClassRecord.pb.usbCompletion = (USBCompletion)kUSBNoCallBack;
  3069.         printerClassRecord.delayInProgress = true;        // this prevents the control pipe completion procptr from being checked
  3070.         USBDeallocMem(&printerClassRecord.pb);
  3071.         
  3072.         printerClassRecord.pCapabilityString = printerClassRecord.capability;
  3073.         return (OSStatus) kUSBDeviceBusy;
  3074.     }
  3075.  
  3076.     //
  3077.     //    don't need to hang on to param blocks after we've gone away
  3078.     //
  3079.     UnholdMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  3080.  
  3081.     USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Ready for removal", 0);
  3082.     return kUSBNoErr;
  3083. }
  3084.  
  3085. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3086.     Name:        CFMInitialization
  3087.  
  3088.     Input Parameters:    
  3089.         initBlock
  3090.         
  3091.     Output Parameters:
  3092.         printerClassDriverFileSpec        set global
  3093.         
  3094.     Description:
  3095.         We use the code fragment initialization to get our filespec which 
  3096.         LoadResources will use to open our resource fork.
  3097.         
  3098.         A peculiarity of the USB 1.0 implementation is that does not lock the
  3099.         driver into physical memory. As a result a driver which does not call
  3100.         SetDriverClosureMemory on it's fragment will likely be paged in during
  3101.         interrupt time and a double bus-fault will occur. The solution for this
  3102.         is to have the USB Expert call SetDriverClosureMemory in a future release
  3103.         of the USB stack. In the meantime, we call it on ourselves to lock us into
  3104.         physical memory. When the USB stack is revved, one call to SetDriverClosureMemory
  3105.         (either this one or the Expert's) will be treated as a NOP.
  3106.  
  3107.     Change History:
  3108.         31 Jul 1998,    oja:        added call to SetDriverClosureMemory
  3109.         11 Jun 1998,    oja:        Original version.
  3110. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3111. OSErr
  3112. CFMInitialization( CFragInitBlock *initBlock )
  3113. {
  3114.     //
  3115.     //    get a reference to our file so that we can open up the resource fork later on
  3116.     //
  3117.     if ( CFragHasFileLocation( initBlock->fragLocator.where ) )
  3118.         printerClassDriverFileSpec = *(initBlock->fragLocator.u.onDisk.fileSpec);
  3119.  
  3120.     // don't page us, we're a device driver
  3121.     return SetDriverClosureMemory( (CFragConnectionID) initBlock->closureID, true );
  3122.  
  3123. }
  3124.  
  3125. // eof
  3126.